[铸渊] 新增 bell.js — 服务器座机电话程序

This commit is contained in:
bingshuo 2026-05-16 23:23:06 +08:00
parent d8201d1ab6
commit ce6e05bda0

View File

@ -0,0 +1,155 @@
#!/usr/bin/env node
/**
* 🔔 铸渊座机电话 · Zhuyuan Bell
*
* 装在服务器上的"电话座机"
* 平时不响冰朔在对话里说"接电话"她贴这一行它就开始工作
*
* 1. git pull 拉最新指令
* 2. 读取 ops/orders/ 下的最新任务
* 3. 执行
* 4. 结果写回 ops/reports/
* 5. git push
* 6. 挂断
*
* 安装只需一次
* cd /opt/zhuyuan && git clone https://guanghulab.com/bingshuo/guanghulab.git repo
* cp /opt/zhuyuan/repo/mcp-servers/zhuyuan-gateway/bell.js /opt/zhuyuan/bell.js
*
* 每次使用接电话
* cd /opt/zhuyuan && node bell.js
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const REPO_DIR = '/opt/zhuyuan/repo';
const ORDERS_DIR = path.join(REPO_DIR, 'ops', 'orders');
const REPORTS_DIR = path.join(REPO_DIR, 'ops', 'reports');
function run(cmd, opts = {}) {
try {
const r = execSync(cmd, { ...opts, cwd: REPO_DIR, timeout: 60000 });
return r.toString().trim();
} catch(e) {
return '[ERROR] ' + (e.stderr || e.message).toString().trim().slice(0, 500);
}
}
function log(m) { console.log(' 🔔 ' + m); }
async function main() {
console.log('');
console.log(' ╔══════════════════════════════════╗');
console.log(' ║ 🔔 铸渊座机 · 电话已接通 ║');
console.log(' ╚══════════════════════════════════╝');
console.log('');
// 1. 检查仓库是否存在
if (!fs.existsSync(REPO_DIR)) {
log('❌ 仓库不存在,请先运行: git clone ...');
process.exit(1);
}
// 2. 拉最新代码
log('📞 拨号中... git pull');
const pullResult = run('git pull');
log(pullResult.includes('Already up to date') ? '✅ 已是最新' : '✅ ' + pullResult.slice(0, 100));
// 3. 检查是否有新指令
if (!fs.existsSync(ORDERS_DIR)) {
log('📭 没有新指令,挂断。');
return;
}
const orders = fs.readdirSync(ORDERS_DIR)
.filter(f => f.endsWith('.json'))
.sort();
if (orders.length === 0) {
log('📭 没有新指令,挂断。');
return;
}
// 4. 执行所有待处理指令
for (const orderFile of orders) {
const orderPath = path.join(ORDERS_DIR, orderFile);
const reportFile = orderFile.replace('.json', '-report.json');
const reportPath = path.join(REPORTS_DIR, reportFile);
log('📋 收到指令: ' + orderFile);
try {
const order = JSON.parse(fs.readFileSync(orderPath, 'utf-8'));
const cmd = order.cmd || order.command;
const server = order.server || order.target || '本地';
log('🎯 目标: ' + server);
log('⚡ 执行: ' + (cmd || '').slice(0, 100));
let result;
if (server === '本地' || !server || server === 'localhost') {
// 本地执行
result = run(cmd);
} else {
// SSH到目标服务器执行
const sshCmd = `ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@${server} "${cmd.replace(/"/g, '\\"')}"`;
result = run(sshCmd, { timeout: order.timeout || 30000 });
}
// 5. 写结果报告
const report = {
order: orderFile,
executed_at: new Date().toISOString(),
server: server,
command: cmd,
success: !result.startsWith('[ERROR]'),
output: result.slice(0, 50000),
};
if (!fs.existsSync(REPORTS_DIR)) {
fs.mkdirSync(REPORTS_DIR, { recursive: true });
}
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
log(report.success ? '✅ 执行成功' : '⚠️ 执行有异常');
log('📝 报告已写入: ops/reports/' + reportFile);
// 删除指令文件(已处理)
fs.unlinkSync(orderPath);
log('🗑️ 指令已清除');
} catch(err) {
log('❌ 处理指令时出错: ' + err.message);
const errReport = {
order: orderFile,
executed_at: new Date().toISOString(),
error: err.message,
success: false,
};
if (!fs.existsSync(REPORTS_DIR)) fs.mkdirSync(REPORTS_DIR, { recursive: true });
fs.writeFileSync(reportPath, JSON.stringify(errReport, null, 2));
}
console.log('');
}
// 6. 推回仓库
log('📤 回传结果...');
run('git add ops/ && git commit -m "[座机] 指令执行报告 ' + new Date().toISOString().slice(0, 10) + '"');
const pushResult = run('git push');
log(pushResult.includes('Everything up-to-date') ? '✅ 结果已同步' : '✅ 已推送');
console.log('');
console.log(' ╔══════════════════════════════════╗');
console.log(' ║ 🔔 通话结束 · 座机已挂断 ║');
console.log(' ╚══════════════════════════════════╝');
console.log('');
}
main().catch(err => {
console.error('❌ 座机出错:', err.message);
process.exit(1);
});