xincbot
Version:
A flexible QQ bot framework based on NapCat and node-napcat-ts
300 lines (284 loc) • 9.83 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const prompts_1 = __importDefault(require("prompts"));
const config_1 = require("./core/config");
const bot_1 = require("./core/bot");
// 版本信息从 package.json 获取
const packageJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '../package.json'), 'utf8'));
commander_1.program
.name('xinc')
.description('xincBot - A flexible QQ bot framework')
.version(packageJson.version);
// 初始化命令
commander_1.program
.command('init')
.description('Initialize xincBot configuration')
.action(async () => {
console.log('欢迎使用 xincBot 配置向导!');
console.log('这将帮助你创建一个基本的配置文件。');
const configManager = new config_1.ConfigManager();
const configPath = path_1.default.join(process.cwd(), 'xinc.config.toml');
// 检查配置文件是否已存在
const configExists = fs_1.default.existsSync(configPath);
// 如果配置文件已存在,询问是否覆盖
if (configExists) {
const { overwrite } = await (0, prompts_1.default)({
type: 'confirm',
name: 'overwrite',
message: '配置文件已存在,是否覆盖?',
initial: false
});
if (!overwrite) {
console.log('配置向导已取消。');
process.exit(0);
}
}
// 收集配置信息
const responses = await (0, prompts_1.default)([
{
type: 'text',
name: 'host',
message: '请输入 NapCat 服务器地址:',
initial: '127.0.0.1'
},
{
type: 'number',
name: 'port',
message: '请输入 NapCat 服务器端口:',
initial: 4001
},
{
type: 'text',
name: 'prefix',
message: '请输入命令前缀:',
initial: '#'
},
{
type: 'text',
name: 'root',
message: '请输入主人QQ号(多个用逗号分隔):',
validate: value => value.trim() !== '' ? true : '至少需要一个主人QQ号'
}
]);
// 处理用户输入
const config = {
host: responses.host,
port: responses.port,
prefix: responses.prefix,
root: responses.root.split(',').map((id) => id.trim()),
admin: [],
plugins: [] // 不再包含 cmd 插件
};
// 创建插件目录
const pluginsDir = path_1.default.join(process.cwd(), 'plugins');
if (!fs_1.default.existsSync(pluginsDir)) {
fs_1.default.mkdirSync(pluginsDir, { recursive: true });
}
// 创建示例插件
createTemplatePlugin(pluginsDir);
// 创建或更新 package.json
const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
let packageJson = {};
// 检查 package.json 是否存在
if (fs_1.default.existsSync(packageJsonPath)) {
try {
packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf8'));
}
catch (error) {
console.error('无法解析现有的 package.json 文件,将创建新文件');
packageJson = {};
}
}
// 确保有 scripts 部分
packageJson.scripts = packageJson.scripts || {};
// 添加启动脚本
packageJson.scripts.start = "npx xinc start";
packageJson.scripts.dev = "npx xinc start";
// 写入 package.json
fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
// 保存配置 - 移到这里,确保在创建示例插件后才写入配置文件
fs_1.default.writeFileSync(configPath, configManager.convertToToml(config));
// 在 createTemplatePlugin 函数后添加
function createIndexFile(dir) {
const indexPath = path_1.default.join(dir, 'index.js');
// 如果文件已存在,不覆盖
if (fs_1.default.existsSync(indexPath)) {
return;
}
const content = `#!/usr/bin/env node
// xincBot 启动文件
const { spawn } = require('child_process');
// 启动 xincBot
const bot = spawn('npx', ['xinc', 'start'], {
stdio: 'inherit',
shell: true
});
// 处理进程退出
bot.on('close', (code) => {
console.log(\`xincBot 进程已退出,退出码: \${code}\`);
process.exit(code);
});
// 处理信号
process.on('SIGINT', () => {
bot.kill('SIGINT');
});
process.on('SIGTERM', () => {
bot.kill('SIGTERM');
});
`;
fs_1.default.writeFileSync(indexPath, content);
console.log('已创建启动文件: index.js');
}
// 然后在 init 命令中调用
// 在创建示例插件后添加
createIndexFile(process.cwd());
console.log('配置文件已创建: xinc.config.toml');
console.log('已创建示例插件: plugins/example');
console.log('已创建启动文件: index.js');
console.log('\n启动方式:');
console.log('1. npm start - 直接启动');
console.log('2. node index.js - 使用 Node 启动');
console.log('3. pm2 start index.js - 使用 PM2 后台运行');
process.exit(0);
});
// 启动命令
commander_1.program
.command('start', { isDefault: true })
.description('Start xincBot')
.action(() => {
console.log('正在启动 xincBot...');
const bot = new bot_1.Bot();
bot.start().catch((error) => {
console.error('启动失败:', error);
process.exit(1);
});
});
// 在 program 定义部分添加新命令
commander_1.program
.command('new <plugin-name>')
.description('Create a new plugin template')
.action((pluginName) => {
console.log(`正在创建插件: ${pluginName}`);
// 创建插件目录
const pluginsDir = path_1.default.join(process.cwd(), 'plugins');
if (!fs_1.default.existsSync(pluginsDir)) {
fs_1.default.mkdirSync(pluginsDir, { recursive: true });
}
const pluginDir = path_1.default.join(pluginsDir, pluginName);
// 检查插件是否已存在
if (fs_1.default.existsSync(pluginDir)) {
console.error(`错误: 插件 "${pluginName}" 已存在`);
process.exit(1);
}
// 创建插件目录
fs_1.default.mkdirSync(pluginDir, { recursive: true });
// 创建插件文件
const pluginContent = `import { definePlugin } from 'xincbot';
export default definePlugin({
name: '${pluginName}',
version: '1.0.0',
desc: '${pluginName} 插件',
setup(ctx) {
// 在这里编写你的插件逻辑
ctx.handle('message', async e => {
// 示例: 响应特定消息
const text = ctx.getText(e);
if (text === '${pluginName}') {
await ctx.respond(e, ['你好,这是 ${pluginName} 插件!']);
}
});
// 你可以处理更多事件
ctx.handle('notice', async e => {
// 处理通知事件
});
// 返回清理函数(可选)
return () => {
console.log('${pluginName} 插件已卸载');
};
}
});
`;
fs_1.default.writeFileSync(path_1.default.join(pluginDir, 'index.ts'), pluginContent);
// 创建 README.md
const readmeContent = `# ${pluginName}
## 描述
${pluginName} 插件
## 功能
- 功能1
- 功能2
## 使用方法
- 命令1: 描述
- 命令2: 描述
## 配置
\`\`\`toml
# 在 xinc.config.toml 中添加:
[plugins.${pluginName}]
# 在这里添加插件配置
\`\`\`
`;
fs_1.default.writeFileSync(path_1.default.join(pluginDir, 'README.md'), readmeContent);
console.log(`插件 "${pluginName}" 创建成功!`);
console.log(`插件目录: ${pluginDir}`);
console.log('要启用此插件,请编辑 xinc.config.toml 文件,在 plugins 数组中添加 "${pluginName}"');
});
commander_1.program.parse();
// 在 cli.ts 中添加创建模板插件的函数
function createTemplatePlugin(pluginsDir) {
const examplePluginDir = path_1.default.join(pluginsDir, 'example');
// 创建插件目录
if (!fs_1.default.existsSync(examplePluginDir)) {
fs_1.default.mkdirSync(examplePluginDir, { recursive: true });
}
// 创建插件文件
const pluginContent = `import { definePlugin } from 'xincbot';
export default definePlugin({
name: 'example',
version: '1.0.0',
desc: '示例插件 - 回复"你好"',
setup(ctx) {
ctx.handle('message', async e => {
// 获取消息文本
const text = ctx.getText(e);
// 如果消息是"你好",回复"你好!我是 xincBot"
if (text === '你好') {
await ctx.respond(e, ['你好!我是 xincBot']);
}
});
}
});
`;
fs_1.default.writeFileSync(path_1.default.join(examplePluginDir, 'index.ts'), pluginContent);
console.log('已创建示例插件: plugins/example');
}
function createPM2Config(dir) {
const configPath = path_1.default.join(dir, 'ecosystem.config.js');
// 如果文件已存在,不覆盖
if (fs_1.default.existsSync(configPath)) {
return;
}
const content = `module.exports = {
apps: [{
name: 'xincBot',
script: 'index.js',
watch: false,
autorestart: true,
max_memory_restart: '1G',
env: {
NODE_ENV: 'production'
}
}]
};
`;
fs_1.default.writeFileSync(configPath, content);
console.log('已创建 PM2 配置文件: ecosystem.config.js');
}
// 然后在 init 命令中调用
createPM2Config(process.cwd());
//# sourceMappingURL=cli.js.map