#!/usr/bin/env node /* eslint-disable max-len */ import { program } from 'commander'; import { PushApi } from './index'; import { QQBotEvent } from './QQBotEvent'; import * as fs from 'fs'; import * as path from 'path'; interface CLIOptions { config: string; message: string; configFile?: string; title?: string; } interface PushResult { name: string; result: { status: number; statusText?: string; }; } program .name('allpush') .version('1.5.0') .description('多平台推送通知 CLI 工具,基于 all-pusher-api'); program .command('send') .description('向配置的推送平台发送消息') .option('-c, --config ', 'JSON 配置字符串,需对引号进行转义。在线生成: https://configer.hclonely.com/?fileLink=https://raw.githubusercontent.com/HCLonely/all-pusher-api/main/config/template.yaml.js') .option('-f, --config-file ', 'JSON 配置文件路径。在线生成: https://configer.hclonely.com/?fileLink=https://raw.githubusercontent.com/HCLonely/all-pusher-api/main/config/template.yaml.js') .requiredOption('-m, --message ', '要发送的消息内容') .option('-t, --title ', '消息标题') .action(async (options: CLIOptions) => { try { if (!options.config && !options.configFile) { console.error('错误:必须提供 --config 或 --config-file 参数!'); process.exit(1); } if (options.config && options.configFile) { console.warn('警告:同时提供了 --config 和 --config-file,后者将被忽略!'); } let config; if (options.config) { config = JSON.parse(options.config); } else if (options.configFile) { const configPath = path.resolve(process.cwd(), options.configFile); const raw = fs.readFileSync(configPath, 'utf8'); config = JSON.parse(raw); } if (!Array.isArray(config)) { config = [config]; } const pusher = new PushApi(config); const results: PushResult[] = await pusher.send({ message: options.message, title: options.title }); console.log('\n推送结果:'); results.forEach(({ name, result }) => { const status = result.status >= 200 && result.status < 300 ? '成功' : '失败'; console.log(`• ${name}: ${status} (${result.status})`); if (result.statusText) { console.log(` 详情: ${result.statusText}`); } if (status === '失败') { console.dir(result, { depth: null }); } }); } catch (error: any) { console.error('发生错误:', error.message); console.error('错误详情:', error.stack); process.exit(1); } }); program .command('listen') .description('通过 WebSocket 订阅并监听 QQ 机器人事件,接收到事件时输出到控制台') .option('--app-id ', 'QQ 机器人 AppID') .option('--app-secret ', 'QQ 机器人 AppSecret') .option('--intents ', '订阅事件类型,逗号分隔', 'GUILDS,GUILD_MEMBERS,GUILD_MESSAGES,GUILD_MESSAGE_REACTIONS,DIRECT_MESSAGE,GROUP_AND_C2C_EVENT,INTERACTION,MESSAGE_AUDIT,FORUMS_EVENT,AUDIO_ACTION,PUBLIC_GUILD_MESSAGES') .option('--shard ', '分片参数,格式: index,total (如 0,1)', '0,1') .option('--list-intents', '列出所有可用的 Intents 事件类型') .action(async (options) => { try { if (options.listIntents) { QQBotEvent.listIntents(); process.exit(0); } if (!options.appId) { console.error('错误:必须提供 --app-id 参数!'); process.exit(1); } if (!options.appSecret) { console.error('错误:必须提供 --app-secret 参数!'); process.exit(1); } const intentKeys = options.intents.split(',').map((s: string) => s.trim()).filter(Boolean); const intents = QQBotEvent.parseIntents(intentKeys); const shardParts = options.shard.split(',').map(Number); if (shardParts.length !== 2 || shardParts.some(isNaN)) { console.error('错误:--shard 格式必须为 "index,total",如 "0,1"'); process.exit(1); } const shard: [number, number] = [shardParts[0], shardParts[1]]; console.error(`启动 QQ 机器人事件监听: intents=${intentKeys.join(',')}(${intents}), shard=[${shard}]`); const event = new QQBotEvent({ appId: options.appId, appSecret: options.appSecret, intents, shard }); process.on('SIGINT', () => { console.error('\n收到中断信号,正在关闭...'); event.stop(); process.exit(0); }); process.on('SIGTERM', () => { console.error('收到终止信号,正在关闭...'); event.stop(); process.exit(0); }); await event.start(); } catch (error: any) { console.error('发生错误:', error.message); process.exit(1); } }); program.parse(process.argv);