easy-cc-api-switch 1.0.0
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/LICENSE +21 -0
- package/README.md +146 -0
- package/health.js +294 -0
- package/index.js +646 -0
- package/notify.js +516 -0
- package/package.json +39 -0
package/notify.js
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通知功能模块
|
|
3
|
+
* 处理企微机器人通知相关的所有功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
const https = require('https');
|
|
12
|
+
|
|
13
|
+
// 配置文件路径
|
|
14
|
+
const CONFIG_DIR = path.join(os.homedir(), '.claude');
|
|
15
|
+
const NOTIFY_CONFIG_FILE = path.join(CONFIG_DIR, 'notify.json');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 创建readline接口
|
|
19
|
+
* @returns {readline.Interface} readline接口
|
|
20
|
+
*/
|
|
21
|
+
function createReadlineInterface() {
|
|
22
|
+
return readline.createInterface({
|
|
23
|
+
input: process.stdin,
|
|
24
|
+
output: process.stdout
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 确保配置目录存在
|
|
30
|
+
*/
|
|
31
|
+
function ensureConfigDir() {
|
|
32
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
33
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
34
|
+
console.log(chalk.green(`创建配置目录: ${CONFIG_DIR}`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 读取通知配置文件
|
|
40
|
+
* @returns {Object} 通知配置对象
|
|
41
|
+
*/
|
|
42
|
+
function readNotifyConfig() {
|
|
43
|
+
try {
|
|
44
|
+
if (!fs.existsSync(NOTIFY_CONFIG_FILE)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const data = fs.readFileSync(NOTIFY_CONFIG_FILE, 'utf8');
|
|
49
|
+
return JSON.parse(data);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(chalk.red(`读取通知配置文件失败: ${error.message}`));
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 保存通知配置文件
|
|
58
|
+
* @param {Object} config 通知配置对象
|
|
59
|
+
*/
|
|
60
|
+
function saveNotifyConfig(config) {
|
|
61
|
+
try {
|
|
62
|
+
ensureConfigDir();
|
|
63
|
+
fs.writeFileSync(NOTIFY_CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
|
|
64
|
+
console.log(chalk.green(`通知配置已保存到: ${NOTIFY_CONFIG_FILE}`));
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(chalk.red(`保存通知配置文件失败: ${error.message}`));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 发送企微机器人通知
|
|
73
|
+
* @param {string} webhookUrl 企微机器人webhook地址
|
|
74
|
+
* @param {string} message 通知消息
|
|
75
|
+
*/
|
|
76
|
+
function sendWeChatWorkNotification(webhookUrl, message) {
|
|
77
|
+
const postData = JSON.stringify({
|
|
78
|
+
msgtype: 'text',
|
|
79
|
+
text: {
|
|
80
|
+
content: message
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const url = new URL(webhookUrl);
|
|
85
|
+
const options = {
|
|
86
|
+
hostname: url.hostname,
|
|
87
|
+
port: url.port || 443,
|
|
88
|
+
path: url.pathname + url.search,
|
|
89
|
+
method: 'POST',
|
|
90
|
+
headers: {
|
|
91
|
+
'Content-Type': 'application/json',
|
|
92
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const req = https.request(options, (res) => {
|
|
97
|
+
let data = '';
|
|
98
|
+
res.on('data', (chunk) => {
|
|
99
|
+
data += chunk;
|
|
100
|
+
});
|
|
101
|
+
res.on('end', () => {
|
|
102
|
+
try {
|
|
103
|
+
const response = JSON.parse(data);
|
|
104
|
+
if (response.errcode === 0) {
|
|
105
|
+
console.log(chalk.green('✓ 企微通知发送成功'));
|
|
106
|
+
} else {
|
|
107
|
+
console.error(chalk.red(`企微通知发送失败: ${response.errmsg}`));
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error(chalk.red(`解析企微响应失败: ${error.message}`));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
req.on('error', (error) => {
|
|
116
|
+
console.error(chalk.red(`企微通知发送失败: ${error.message}`));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
req.write(postData);
|
|
120
|
+
req.end();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 创建企微通知Hook脚本
|
|
125
|
+
* @param {string} scriptPath Hook脚本的完整路径
|
|
126
|
+
*/
|
|
127
|
+
function createWeChatNotifyScript(scriptPath) {
|
|
128
|
+
const scriptContent = `#!/usr/bin/env node
|
|
129
|
+
/**
|
|
130
|
+
* ClaudeCode企微通知Hook脚本
|
|
131
|
+
* 由claude-code-switch自动生成
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
const https = require('https');
|
|
135
|
+
const fs = require('fs');
|
|
136
|
+
const path = require('path');
|
|
137
|
+
|
|
138
|
+
const NOTIFY_CONFIG_PATH = path.join(require('os').homedir(), '.claude', 'notify.json');
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 发送企微机器人通知
|
|
142
|
+
* @param {string} webhookUrl 企微机器人webhook地址
|
|
143
|
+
* @param {string} message 通知消息
|
|
144
|
+
*/
|
|
145
|
+
function sendWeChatWorkNotification(webhookUrl, message) {
|
|
146
|
+
const postData = JSON.stringify({
|
|
147
|
+
msgtype: 'text',
|
|
148
|
+
text: {
|
|
149
|
+
content: message
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const url = new URL(webhookUrl);
|
|
154
|
+
const options = {
|
|
155
|
+
hostname: url.hostname,
|
|
156
|
+
port: url.port || 443,
|
|
157
|
+
path: url.pathname + url.search,
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const req = https.request(options, (res) => {
|
|
166
|
+
let data = '';
|
|
167
|
+
res.on('data', (chunk) => {
|
|
168
|
+
data += chunk;
|
|
169
|
+
});
|
|
170
|
+
res.on('end', () => {
|
|
171
|
+
try {
|
|
172
|
+
const response = JSON.parse(data);
|
|
173
|
+
if (response.errcode !== 0) {
|
|
174
|
+
console.error('企微通知发送失败:', response.errmsg);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('解析企微响应失败:', error.message);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
req.on('error', (error) => {
|
|
183
|
+
console.error('企微通知发送失败:', error.message);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
req.write(postData);
|
|
187
|
+
req.end();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 读取通知配置
|
|
192
|
+
*/
|
|
193
|
+
function readNotifyConfig() {
|
|
194
|
+
try {
|
|
195
|
+
if (fs.existsSync(NOTIFY_CONFIG_PATH)) {
|
|
196
|
+
const data = fs.readFileSync(NOTIFY_CONFIG_PATH, 'utf8');
|
|
197
|
+
return JSON.parse(data);
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('读取通知配置失败:', error.message);
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 处理命令行参数
|
|
206
|
+
const eventType = process.argv[2];
|
|
207
|
+
const config = readNotifyConfig();
|
|
208
|
+
|
|
209
|
+
// 检查是否启用通知
|
|
210
|
+
if (!config || !config.wechatWork?.enabled || !config.wechatWork?.webhookUrl) {
|
|
211
|
+
process.exit(0);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 检查特定事件是否启用
|
|
215
|
+
if (config.hooks?.events?.[eventType]?.enabled === false) {
|
|
216
|
+
process.exit(0);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 读取stdin获取事件数据
|
|
220
|
+
let inputData = '';
|
|
221
|
+
process.stdin.on('data', (chunk) => {
|
|
222
|
+
inputData += chunk;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
process.stdin.on('end', () => {
|
|
226
|
+
try {
|
|
227
|
+
const eventData = JSON.parse(inputData);
|
|
228
|
+
let message = '';
|
|
229
|
+
|
|
230
|
+
if (eventType === 'notification') {
|
|
231
|
+
message = \`[Claude Code通知]\\n时间: \${new Date().toLocaleString()}\\n\${config.hooks?.events?.Notification?.message || 'Claude Code需要您的关注'}\\n会话ID: \${eventData.session_id || 'unknown'}\`;
|
|
232
|
+
|
|
233
|
+
// 如果有payload消息,添加到通知中
|
|
234
|
+
if (eventData.payload?.message) {
|
|
235
|
+
message += \`\\n消息: \${eventData.payload.message.substring(0, 100)}\${eventData.payload.message.length > 100 ? '...' : ''}\`;
|
|
236
|
+
}
|
|
237
|
+
} else if (eventType === 'stop') {
|
|
238
|
+
message = \`[Claude Code完成]\\n时间: \${new Date().toLocaleString()}\\n\${config.hooks?.events?.Stop?.message || 'Claude Code任务已完成'}\\n会话ID: \${eventData.session_id || 'unknown'}\`;
|
|
239
|
+
|
|
240
|
+
if (eventData.cwd) {
|
|
241
|
+
message += \`\\n工作目录: \${eventData.cwd}\`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (message && config.wechatWork?.webhookUrl) {
|
|
246
|
+
sendWeChatWorkNotification(config.wechatWork.webhookUrl, message);
|
|
247
|
+
}
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error('处理事件数据失败:', error.message);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
`;
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
fs.writeFileSync(scriptPath, scriptContent, 'utf8');
|
|
256
|
+
// 设置可执行权限
|
|
257
|
+
fs.chmodSync(scriptPath, 0o755);
|
|
258
|
+
console.log(chalk.green(`✓ Hook脚本已创建: ${scriptPath}`));
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error(chalk.red(`创建Hook脚本失败: ${error.message}`));
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* 设置ClaudeCode Hooks配置
|
|
267
|
+
* @param {Object} config 通知配置对象
|
|
268
|
+
*/
|
|
269
|
+
function setupClaudeCodeHooks(config) {
|
|
270
|
+
const claudeSettingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
271
|
+
const scriptsDir = path.join(os.homedir(), '.claude', 'scripts');
|
|
272
|
+
const hookScriptPath = path.join(scriptsDir, 'wechat-notify.js');
|
|
273
|
+
|
|
274
|
+
console.log(chalk.cyan('\n正在配置ClaudeCode Hooks...'));
|
|
275
|
+
|
|
276
|
+
// 确保scripts目录存在
|
|
277
|
+
if (!fs.existsSync(scriptsDir)) {
|
|
278
|
+
fs.mkdirSync(scriptsDir, { recursive: true });
|
|
279
|
+
console.log(chalk.green(`创建scripts目录: ${scriptsDir}`));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 检查hook脚本是否存在,不存在则创建
|
|
283
|
+
if (!fs.existsSync(hookScriptPath)) {
|
|
284
|
+
console.log(chalk.yellow(`Hook脚本不存在,正在创建: ${hookScriptPath}`));
|
|
285
|
+
createWeChatNotifyScript(hookScriptPath);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 读取现有的Claude设置
|
|
289
|
+
let claudeSettings = {};
|
|
290
|
+
if (fs.existsSync(claudeSettingsPath)) {
|
|
291
|
+
try {
|
|
292
|
+
const data = fs.readFileSync(claudeSettingsPath, 'utf8');
|
|
293
|
+
claudeSettings = JSON.parse(data);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.warn(chalk.yellow(`读取Claude设置文件失败,将创建新的设置: ${error.message}`));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// 确保hooks配置存在
|
|
300
|
+
if (!claudeSettings.hooks) {
|
|
301
|
+
claudeSettings.hooks = {};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// 配置Notification和Stop事件的hooks
|
|
305
|
+
claudeSettings.hooks.Notification = [
|
|
306
|
+
{
|
|
307
|
+
hooks: [
|
|
308
|
+
{
|
|
309
|
+
type: 'command',
|
|
310
|
+
command: `node "${hookScriptPath}" notification`
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
claudeSettings.hooks.Stop = [
|
|
317
|
+
{
|
|
318
|
+
hooks: [
|
|
319
|
+
{
|
|
320
|
+
type: 'command',
|
|
321
|
+
command: `node "${hookScriptPath}" stop`
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
// 保存Claude设置
|
|
328
|
+
try {
|
|
329
|
+
fs.writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2), 'utf8');
|
|
330
|
+
console.log(chalk.green('✓ ClaudeCode Hooks配置已更新'));
|
|
331
|
+
console.log(chalk.white(`Hook脚本位置: ${hookScriptPath}`));
|
|
332
|
+
console.log(chalk.green('\n配置完成!现在ClaudeCode将在以下事件时发送企微通知:'));
|
|
333
|
+
console.log(chalk.white(' - Notification事件: 当Claude需要用户关注时'));
|
|
334
|
+
console.log(chalk.white(' - Stop事件: 当Claude任务完成时'));
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error(chalk.red(`保存Claude设置文件失败: ${error.message}`));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* 设置通知配置
|
|
342
|
+
*/
|
|
343
|
+
function setupNotifyConfig() {
|
|
344
|
+
const rl = createReadlineInterface();
|
|
345
|
+
|
|
346
|
+
console.log(chalk.cyan('\n设置企微机器人通知配置:'));
|
|
347
|
+
console.log(chalk.white('请在企微群聊中添加机器人,获取Webhook地址'));
|
|
348
|
+
console.log(chalk.white('格式: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY'));
|
|
349
|
+
console.log(chalk.yellow('配置完成后,将自动通过ClaudeCode Hooks监听Notification和Stop事件'));
|
|
350
|
+
|
|
351
|
+
rl.question(chalk.cyan('\n请输入企微机器人Webhook地址: '), (webhookUrl) => {
|
|
352
|
+
if (!webhookUrl || !webhookUrl.startsWith('https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=')) {
|
|
353
|
+
console.error(chalk.red('无效的企微机器人Webhook地址'));
|
|
354
|
+
rl.close();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const config = {
|
|
359
|
+
wechatWork: {
|
|
360
|
+
webhookUrl: webhookUrl,
|
|
361
|
+
enabled: true,
|
|
362
|
+
events: ['Notification', 'Stop'] // 支持的事件类型
|
|
363
|
+
},
|
|
364
|
+
hooks: {
|
|
365
|
+
enabled: true,
|
|
366
|
+
defaultEnabled: true, // 默认开启通知
|
|
367
|
+
events: {
|
|
368
|
+
Notification: {
|
|
369
|
+
enabled: true,
|
|
370
|
+
message: 'Claude Code需要您的关注'
|
|
371
|
+
},
|
|
372
|
+
Stop: {
|
|
373
|
+
enabled: true,
|
|
374
|
+
message: 'Claude Code任务已完成'
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
// 为未来支持更多通知渠道预留配置结构
|
|
379
|
+
telegram: {
|
|
380
|
+
enabled: false
|
|
381
|
+
},
|
|
382
|
+
slack: {
|
|
383
|
+
enabled: false
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
saveNotifyConfig(config);
|
|
388
|
+
setupClaudeCodeHooks(config);
|
|
389
|
+
rl.close();
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* 显示通知配置状态
|
|
395
|
+
*/
|
|
396
|
+
function showNotifyStatus() {
|
|
397
|
+
const notifyConfig = readNotifyConfig();
|
|
398
|
+
|
|
399
|
+
if (!notifyConfig) {
|
|
400
|
+
console.log(chalk.yellow('未配置企微通知,请运行 ccs notify setup 进行配置'));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
console.log(chalk.cyan('\n当前通知配置状态:'));
|
|
405
|
+
console.log(chalk.white('企微机器人: ') + (notifyConfig.wechatWork?.enabled ? chalk.green('已启用') : chalk.red('未启用')));
|
|
406
|
+
|
|
407
|
+
if (notifyConfig.wechatWork?.webhookUrl) {
|
|
408
|
+
const maskedUrl = notifyConfig.wechatWork.webhookUrl.replace(/key=([^&]+)/, 'key=***');
|
|
409
|
+
console.log(chalk.white('Webhook地址: ') + maskedUrl);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (notifyConfig.hooks?.enabled) {
|
|
413
|
+
console.log(chalk.white('Hook事件: ') + chalk.green('已启用'));
|
|
414
|
+
console.log(chalk.white(' Notification事件: ') + (notifyConfig.hooks.events?.Notification?.enabled ? chalk.green('启用') : chalk.red('禁用')));
|
|
415
|
+
console.log(chalk.white(' Stop事件: ') + (notifyConfig.hooks.events?.Stop?.enabled ? chalk.green('启用') : chalk.red('禁用')));
|
|
416
|
+
} else {
|
|
417
|
+
console.log(chalk.white('Hook事件: ') + chalk.red('未启用'));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 检查ClaudeCode hooks配置文件
|
|
421
|
+
const claudeHooksPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
422
|
+
if (fs.existsSync(claudeHooksPath)) {
|
|
423
|
+
try {
|
|
424
|
+
const claudeSettings = JSON.parse(fs.readFileSync(claudeHooksPath, 'utf8'));
|
|
425
|
+
if (claudeSettings.hooks && claudeSettings.hooks.Notification && claudeSettings.hooks.Stop) {
|
|
426
|
+
console.log(chalk.white('ClaudeCode hooks配置: ') + chalk.green('已配置'));
|
|
427
|
+
} else {
|
|
428
|
+
console.log(chalk.white('ClaudeCode hooks配置: ') + chalk.yellow('未配置 - 需要恢复'));
|
|
429
|
+
}
|
|
430
|
+
} catch (error) {
|
|
431
|
+
console.log(chalk.white('ClaudeCode hooks配置: ') + chalk.red('读取失败'));
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
console.log(chalk.white('ClaudeCode hooks配置: ') + chalk.yellow('未找到'));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 测试企微通知功能
|
|
440
|
+
*/
|
|
441
|
+
function testNotification() {
|
|
442
|
+
const notifyConfig = readNotifyConfig();
|
|
443
|
+
|
|
444
|
+
if (!notifyConfig || !notifyConfig.wechatWork || !notifyConfig.wechatWork.webhookUrl) {
|
|
445
|
+
console.log(chalk.yellow('未配置企微通知,请先运行 ccs notify setup'));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
console.log(chalk.cyan('正在发送测试通知...'));
|
|
450
|
+
const testMessage = `[CCS测试通知]\n时间: ${new Date().toLocaleString()}\n这是一条来自claude-code-switch的测试消息`;
|
|
451
|
+
|
|
452
|
+
sendWeChatWorkNotification(notifyConfig.wechatWork.webhookUrl, testMessage);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* 注册notify相关的CLI命令
|
|
458
|
+
* @param {Object} program commander程序对象
|
|
459
|
+
*/
|
|
460
|
+
function registerNotifyCommands(program) {
|
|
461
|
+
// 新的notify命令,用于配置企微通知
|
|
462
|
+
const notifyCommand = program
|
|
463
|
+
.command('notify')
|
|
464
|
+
.alias('ntf')
|
|
465
|
+
.description('配置企微通知设置');
|
|
466
|
+
|
|
467
|
+
notifyCommand
|
|
468
|
+
.command('setup')
|
|
469
|
+
.description('设置企微机器人webhook地址')
|
|
470
|
+
.action(() => {
|
|
471
|
+
ensureConfigDir();
|
|
472
|
+
setupNotifyConfig();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
notifyCommand
|
|
476
|
+
.command('status')
|
|
477
|
+
.description('查看当前通知配置状态')
|
|
478
|
+
.action(() => {
|
|
479
|
+
ensureConfigDir();
|
|
480
|
+
showNotifyStatus();
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
notifyCommand
|
|
484
|
+
.command('test')
|
|
485
|
+
.description('测试企微通知功能')
|
|
486
|
+
.action(() => {
|
|
487
|
+
ensureConfigDir();
|
|
488
|
+
testNotification();
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// 保留原有的ntf命令作为兼容性(独立命令)
|
|
492
|
+
program
|
|
493
|
+
.command('ntfold')
|
|
494
|
+
.description('(已废弃) 原ntf命令,请使用 ccs notify 命令')
|
|
495
|
+
.action(() => {
|
|
496
|
+
console.log(chalk.yellow('原ntf监听命令已废弃,现在使用ClaudeCode Hooks机制'));
|
|
497
|
+
console.log(chalk.cyan('请使用以下命令:'));
|
|
498
|
+
console.log(chalk.cyan(' ccs notify setup - 设置企微通知'));
|
|
499
|
+
console.log(chalk.cyan(' ccs notify status - 查看通知状态'));
|
|
500
|
+
console.log(chalk.cyan(' ccs notify test - 测试通知功能'));
|
|
501
|
+
console.log(chalk.yellow('\n配置完成后,ClaudeCode将自动发送通知,无需手动启动监听'));
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
module.exports = {
|
|
506
|
+
readNotifyConfig,
|
|
507
|
+
saveNotifyConfig,
|
|
508
|
+
sendWeChatWorkNotification,
|
|
509
|
+
setupClaudeCodeHooks,
|
|
510
|
+
setupNotifyConfig,
|
|
511
|
+
showNotifyStatus,
|
|
512
|
+
testNotification,
|
|
513
|
+
registerNotifyCommands,
|
|
514
|
+
ensureConfigDir,
|
|
515
|
+
createWeChatNotifyScript
|
|
516
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "easy-cc-api-switch",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Claude Code API 配置快速切换工具,支持循环切换配置",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ccs": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude",
|
|
14
|
+
"config",
|
|
15
|
+
"switch",
|
|
16
|
+
"api",
|
|
17
|
+
"cli",
|
|
18
|
+
"anthropic",
|
|
19
|
+
"claude-code"
|
|
20
|
+
],
|
|
21
|
+
"author": "bluemomo112",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/bluemomo112/claude-api-settings-switch-advanced.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/bluemomo112/claude-api-settings-switch-advanced/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/bluemomo112/claude-api-settings-switch-advanced#readme",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"chalk": "^4.1.2",
|
|
33
|
+
"commander": "^11.1.0",
|
|
34
|
+
"inquirer": "^8.2.5"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=14.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|