#!/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); });