144 lines
4.6 KiB
JavaScript
144 lines
4.6 KiB
JavaScript
// scripts/skyeye/asop-executor.js
|
||
// 天眼·ASOP 已批准优化执行器
|
||
//
|
||
// 读取 data/asop-requests/approved/ 下的已批准申请
|
||
// 按优先级逐个执行
|
||
// 执行完成后移动到 executed/
|
||
//
|
||
// 执行原则:
|
||
// ① 执行前保存快照到 snapshots/
|
||
// ② 只执行明确定义的操作
|
||
// ③ 执行后记录结果
|
||
// ④ 绝不做破坏性操作
|
||
|
||
'use strict';
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const ROOT = path.resolve(__dirname, '../..');
|
||
const ASOP_DIR = path.join(ROOT, 'data/asop-requests');
|
||
const APPROVED_DIR = path.join(ASOP_DIR, 'approved');
|
||
const EXECUTED_DIR = path.join(ASOP_DIR, 'executed');
|
||
const SNAPSHOTS_DIR = path.join(ASOP_DIR, 'snapshots');
|
||
|
||
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
|
||
|
||
// ━━━ 安全读取 JSON ━━━
|
||
function readJSON(filePath) {
|
||
try {
|
||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// ━━━ 保存快照(执行前备份) ━━━
|
||
function saveSnapshot(requestId, affectedFiles) {
|
||
const snapshotDir = path.join(SNAPSHOTS_DIR, requestId);
|
||
fs.mkdirSync(snapshotDir, { recursive: true });
|
||
|
||
for (const file of affectedFiles) {
|
||
const srcPath = path.join(ROOT, file);
|
||
if (fs.existsSync(srcPath)) {
|
||
const destPath = path.join(snapshotDir, file.replace(/\//g, '__'));
|
||
fs.copyFileSync(srcPath, destPath);
|
||
}
|
||
}
|
||
|
||
console.log(`📸 快照已保存: ${requestId} (${affectedFiles.length} 文件)`);
|
||
}
|
||
|
||
// ━━━ 执行单个优化 ━━━
|
||
function executeOptimization(request) {
|
||
const requestId = request.request_id;
|
||
const affectedFiles = (request.impact_assessment && request.impact_assessment.affected_files) || [];
|
||
|
||
console.log(`\n🔧 执行: ${requestId}`);
|
||
console.log(` 方案: ${request.proposed_optimization}`);
|
||
console.log(` 影响: ${affectedFiles.join(', ') || '无文件变更'}`);
|
||
|
||
// 保存快照
|
||
if (affectedFiles.length > 0) {
|
||
saveSnapshot(requestId, affectedFiles);
|
||
}
|
||
|
||
// ASOP 执行器只记录执行意图,实际执行由天眼修复 Agent 统一处理
|
||
// 这样可以避免 ASOP 执行器和修复 Agent 做重复/冲突的操作
|
||
const result = {
|
||
executed: true,
|
||
executed_at: new Date(Date.now() + BEIJING_OFFSET_MS).toISOString().replace('T', ' ').slice(0, 19) + '+08:00',
|
||
executor: '🦅 天眼·ASOP执行器',
|
||
snapshot_saved: affectedFiles.length > 0,
|
||
note: '已记录执行意图,待下次天眼验证效果'
|
||
};
|
||
|
||
console.log(` ✅ 执行完成: ${requestId}`);
|
||
return result;
|
||
}
|
||
|
||
// ━━━ 主执行流程 ━━━
|
||
function executeAll() {
|
||
console.log('🔧 天眼·ASOP 执行器启动');
|
||
console.log('═══════════════════════════════════════════\n');
|
||
|
||
if (!fs.existsSync(APPROVED_DIR)) {
|
||
console.log('ℹ️ approved/ 目录不存在,无待执行优化');
|
||
const result = { total: 0, executed: 0, failed: 0 };
|
||
console.log(JSON.stringify(result, null, 2));
|
||
return result;
|
||
}
|
||
|
||
const files = fs.readdirSync(APPROVED_DIR)
|
||
.filter(f => f.endsWith('.json') && f !== '.gitkeep');
|
||
|
||
if (files.length === 0) {
|
||
console.log('🔧 ASOP:无已批准待执行的优化');
|
||
const result = { total: 0, executed: 0, failed: 0 };
|
||
console.log(JSON.stringify(result, null, 2));
|
||
return result;
|
||
}
|
||
|
||
console.log(`🔧 ASOP:发现 ${files.length} 条已批准待执行的优化\n`);
|
||
|
||
const summary = { total: files.length, executed: 0, failed: 0, results: [] };
|
||
|
||
for (const file of files) {
|
||
const filePath = path.join(APPROVED_DIR, file);
|
||
const req = readJSON(filePath);
|
||
if (!req) {
|
||
console.log(`⚠️ 无法解析 ${file},跳过`);
|
||
continue;
|
||
}
|
||
|
||
try {
|
||
const result = executeOptimization(req);
|
||
req.execution_result = result;
|
||
|
||
// 移动到 executed/
|
||
fs.mkdirSync(EXECUTED_DIR, { recursive: true });
|
||
fs.writeFileSync(path.join(EXECUTED_DIR, file), JSON.stringify(req, null, 2) + '\n');
|
||
fs.unlinkSync(filePath);
|
||
|
||
summary.executed++;
|
||
summary.results.push({ request_id: req.request_id, status: 'executed' });
|
||
} catch (e) {
|
||
console.error(`❌ ${req.request_id} 执行失败: ${e.message}`);
|
||
summary.failed++;
|
||
summary.results.push({ request_id: req.request_id, status: 'failed', error: e.message });
|
||
}
|
||
}
|
||
|
||
console.log(`\n📊 执行结果:成功 ${summary.executed} / 失败 ${summary.failed}`);
|
||
console.log(JSON.stringify(summary, null, 2));
|
||
return summary;
|
||
}
|
||
|
||
// ━━━ 导出 ━━━
|
||
module.exports = { executeAll, saveSnapshot };
|
||
|
||
// ━━━ 直接运行 ━━━
|
||
if (require.main === module) {
|
||
executeAll();
|
||
}
|