guanghulab/openclaw/index.js

406 lines
15 KiB
JavaScript
Raw Normal View History

/**
* openclaw OpenClaw Agent 执行框架
*
* AGE OS v1.0 Phase 1 · Step 3
*
* 核心职责
* 编排完整的唤醒闭环
* 定时触发 唤醒铸渊核心大脑 大脑读取巡检结果
* 大脑判断优先级 大脑驱动修复/写公告 大脑休眠
*
* 核心原则
* 所有自动触发 = 必须先唤醒核心大脑大脑不醒什么都不做
*
* 调用方式
* node openclaw # 完整闭环执行
* node openclaw --dry-run # Dry Run 模式不调用 LLM API
* node openclaw --step wake # 仅唤醒
* node openclaw --step inspect # 仅巡检
* node openclaw --step judge # 仅判断需先有巡检结果
* node openclaw --persona zhuyuan # 指定人格体默认 zhuyuan
*/
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
// ══════════════════════════════════════════════════════════
// Soul 加载器
// ══════════════════════════════════════════════════════════
function loadSoul(personaId) {
const soulPath = path.join(__dirname, 'soul', `${personaId}.json`);
if (!fs.existsSync(soulPath)) {
console.log(`[OPENCLAW] ❌ Soul 文件不存在: ${soulPath}`);
return null;
}
try {
const soul = JSON.parse(fs.readFileSync(soulPath, 'utf-8'));
console.log(`[OPENCLAW] ✅ 已加载 Soul: ${soul.name} (${soul.name_en})`);
return soul;
} catch (err) {
console.log(`[OPENCLAW] ❌ Soul 文件解析失败: ${err.message}`);
return null;
}
}
// ══════════════════════════════════════════════════════════
// Phase 1: 唤醒核心大脑
// ══════════════════════════════════════════════════════════
async function phaseWake(soul, options) {
console.log('');
console.log('[OPENCLAW] ═══ Phase 1: 唤醒核心大脑 ═══');
const brainWake = require(path.join(ROOT, 'core/brain-wake'));
const result = await brainWake.wake({
task: options.task || '闭环巡检',
dryRun: options.dryRun,
persona: soul.persona_id,
});
if (!result.success && !result.dryRun) {
console.log('[OPENCLAW] ❌ 核心大脑唤醒失败 — 闭环终止');
return { success: false, phase: 'wake', error: result.error };
}
console.log('[OPENCLAW] ✅ 核心大脑已唤醒');
return { success: true, phase: 'wake', wakeResult: result };
}
// ══════════════════════════════════════════════════════════
// Phase 2: 执行巡检
// ══════════════════════════════════════════════════════════
function phaseInspect(soul) {
console.log('');
console.log('[OPENCLAW] ═══ Phase 2: 执行巡检 ═══');
const inspectModule = path.join(ROOT, 'scripts/zhuyuan-full-inspection.js');
if (!fs.existsSync(inspectModule)) {
console.log('[OPENCLAW] ❌ 巡检模块不存在');
return { success: false, phase: 'inspect', error: 'inspect_module_not_found' };
}
try {
const inspect = require(inspectModule);
if (typeof inspect.runInspection === 'function') {
const report = inspect.runInspection();
console.log(`[OPENCLAW] ✅ 巡检完成 — 评分: ${report.score || 'N/A'}`);
return { success: true, phase: 'inspect', report };
}
// 如果没有导出 runInspection使用 child_process 运行
const { execSync } = require('child_process');
const output = execSync(`node "${inspectModule}" --json`, {
cwd: ROOT,
encoding: 'utf-8',
timeout: 120000,
});
let report;
try {
report = JSON.parse(output);
} catch (_) {
report = { raw: output };
}
console.log('[OPENCLAW] ✅ 巡检完成');
return { success: true, phase: 'inspect', report };
} catch (err) {
console.log(`[OPENCLAW] ⚠️ 巡检异常: ${err.message}`);
return { success: false, phase: 'inspect', error: err.message };
}
}
// ══════════════════════════════════════════════════════════
// Phase 3: 大脑判断(分析巡检结果,决定修复策略)
// ══════════════════════════════════════════════════════════
async function phaseJudge(soul, inspectResult, wakeResult, options) {
console.log('');
console.log('[OPENCLAW] ═══ Phase 3: 大脑判断 ═══');
if (!inspectResult || !inspectResult.success) {
console.log('[OPENCLAW] ⚠️ 无有效巡检结果,跳过判断');
return { success: true, phase: 'judge', actions: [], skipped: true };
}
const report = inspectResult.report || {};
const actions = [];
// 分析巡检报告中的问题
if (report.areas) {
for (const area of report.areas) {
if (area.issues && area.issues.length > 0) {
for (const issue of area.issues) {
actions.push({
type: issue.fixable ? 'auto-fix' : 'manual',
area: area.name,
description: issue.description || issue.message || String(issue),
priority: issue.priority || 'normal',
});
}
}
}
}
// 分析 score
if (typeof report.score === 'number' && report.score < 70) {
actions.push({
type: 'alert',
area: 'overall',
description: `系统健康评分过低: ${report.score}/100`,
priority: 'high',
});
}
// Dry-run 模式下使用模拟判断
if (options.dryRun) {
console.log(`[OPENCLAW] 🔍 Dry Run — 发现 ${actions.length} 个待处理项`);
return { success: true, phase: 'judge', actions, dryRun: true };
}
// 有可用的 LLM 且有复杂问题时,让大脑分析
if (actions.length > 0 && wakeResult && wakeResult.wakeResult && wakeResult.wakeResult.success) {
console.log(`[OPENCLAW] 🧠 大脑分析 ${actions.length} 个待处理项...`);
// 大脑判断已在唤醒阶段完成上下文加载
// 此处记录判断结果供后续执行
}
console.log(`[OPENCLAW] ✅ 判断完成 — ${actions.length} 个待处理项`);
for (const action of actions) {
const icon = action.type === 'auto-fix' ? '🔧' : action.type === 'alert' ? '🚨' : '📋';
console.log(`[OPENCLAW] ${icon} [${action.priority}] ${action.area}: ${action.description}`);
}
return { success: true, phase: 'judge', actions };
}
// ══════════════════════════════════════════════════════════
// Phase 4: 驱动修复
// ══════════════════════════════════════════════════════════
async function phaseFix(soul, judgeResult, options) {
console.log('');
console.log('[OPENCLAW] ═══ Phase 4: 驱动修复 ═══');
if (!judgeResult || !judgeResult.success || !judgeResult.actions) {
console.log('[OPENCLAW] 无待修复项');
return { success: true, phase: 'fix', fixed: [], skipped: [] };
}
const actions = judgeResult.actions;
const autoFixes = actions.filter(a => a.type === 'auto-fix');
const manualItems = actions.filter(a => a.type !== 'auto-fix');
const fixed = [];
const skipped = [];
if (options.dryRun) {
console.log(`[OPENCLAW] 🔍 Dry Run — 跳过实际修复`);
console.log(`[OPENCLAW] 可自动修复: ${autoFixes.length}`);
console.log(`[OPENCLAW] 需人类介入: ${manualItems.length}`);
return { success: true, phase: 'fix', fixed: [], skipped: actions, dryRun: true };
}
// 执行可自动修复的项
for (const fix of autoFixes) {
try {
console.log(`[OPENCLAW] 🔧 修复: ${fix.area}${fix.description}`);
// 调用 system-check 的自动修复能力
const systemCheck = require(path.join(ROOT, 'core/system-check'));
if (typeof systemCheck.autoFix === 'function') {
systemCheck.autoFix(fix);
}
fixed.push(fix);
} catch (err) {
console.log(`[OPENCLAW] ⚠️ 修复失败: ${err.message}`);
skipped.push({ ...fix, error: err.message });
}
}
// 需人类介入的项记录到公告区
for (const item of manualItems) {
console.log(`[OPENCLAW] 📋 需人类介入: ${item.area}${item.description}`);
skipped.push(item);
}
console.log(`[OPENCLAW] ✅ 修复完成 — 已修复 ${fixed.length} 项,待处理 ${skipped.length}`);
return { success: true, phase: 'fix', fixed, skipped };
}
// ══════════════════════════════════════════════════════════
// Phase 5: 大脑休眠(记录闭环结果)
// ══════════════════════════════════════════════════════════
function phaseSleep(soul, loopResult) {
console.log('');
console.log('[OPENCLAW] ═══ Phase 5: 大脑休眠 ═══');
const timestamp = new Date().toISOString();
const sleepRecord = {
persona: soul.persona_id,
persona_name: soul.name,
timestamp,
loop_success: loopResult.success,
phases_completed: loopResult.phases || [],
actions_taken: loopResult.fixResult ? loopResult.fixResult.fixed.length : 0,
actions_pending: loopResult.fixResult ? loopResult.fixResult.skipped.length : 0,
};
// 写入闭环记录
const recordDir = path.join(__dirname, 'logs');
if (!fs.existsSync(recordDir)) {
fs.mkdirSync(recordDir, { recursive: true });
}
const dateStr = timestamp.slice(0, 10).replace(/-/g, '');
const recordPath = path.join(recordDir, `loop-${dateStr}.json`);
let records = [];
if (fs.existsSync(recordPath)) {
try {
records = JSON.parse(fs.readFileSync(recordPath, 'utf-8'));
if (!Array.isArray(records)) records = [records];
} catch (_) {
records = [];
}
}
records.push(sleepRecord);
fs.writeFileSync(recordPath, JSON.stringify(records, null, 2));
console.log(`[OPENCLAW] 💤 ${soul.name} 核心大脑进入休眠`);
console.log(`[OPENCLAW] 📋 闭环记录已写入: ${recordPath}`);
// 输出到 GITHUB_OUTPUT
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `loop_success=${loopResult.success}\n`);
fs.appendFileSync(outputFile, `actions_taken=${sleepRecord.actions_taken}\n`);
fs.appendFileSync(outputFile, `actions_pending=${sleepRecord.actions_pending}\n`);
}
return sleepRecord;
}
// ══════════════════════════════════════════════════════════
// 完整闭环执行
// ══════════════════════════════════════════════════════════
async function runLoop(options = {}) {
const personaId = options.persona || 'zhuyuan';
const timestamp = new Date().toISOString();
console.log('');
console.log('🔄 ═══════════════════════════════════════════');
console.log(' OpenClaw · AGE OS v1.0 唤醒闭环');
console.log(` 人格体: ${personaId}`);
console.log(` 时间: ${timestamp}`);
console.log(` 模式: ${options.dryRun ? 'Dry Run' : '正式执行'}`);
console.log('═══════════════════════════════════════════════');
// 加载 Soul
const soul = loadSoul(personaId);
if (!soul) {
return { success: false, error: 'soul_not_found', persona: personaId };
}
const phases = [];
let wakeResult, inspectResult, judgeResult, fixResult;
// 单步执行模式
const step = options.step;
// Phase 1: 唤醒
if (!step || step === 'wake') {
wakeResult = await phaseWake(soul, options);
phases.push('wake');
if (!wakeResult.success) {
return { success: false, phases, wakeResult };
}
}
// Phase 2: 巡检
if (!step || step === 'inspect') {
inspectResult = phaseInspect(soul);
phases.push('inspect');
}
// Phase 3: 判断
if (!step || step === 'judge') {
judgeResult = await phaseJudge(soul, inspectResult, wakeResult, options);
phases.push('judge');
}
// Phase 4: 修复
if (!step || step === 'fix') {
fixResult = await phaseFix(soul, judgeResult, options);
phases.push('fix');
}
// Phase 5: 休眠
const loopResult = {
success: true,
phases,
wakeResult,
inspectResult,
judgeResult,
fixResult,
};
if (!step) {
phaseSleep(soul, loopResult);
phases.push('sleep');
}
console.log('');
console.log('═══════════════════════════════════════════════');
console.log(`🔄 OpenClaw 闭环${step ? '(' + step + ')' : ''}完成`);
console.log(` 完成阶段: ${phases.join(' → ')}`);
console.log('═══════════════════════════════════════════════');
console.log('');
return loopResult;
}
// ══════════════════════════════════════════════════════════
// 模块导出
// ══════════════════════════════════════════════════════════
module.exports = {
runLoop,
loadSoul,
phaseWake,
phaseInspect,
phaseJudge,
phaseFix,
phaseSleep,
};
// ══════════════════════════════════════════════════════════
// CLI 入口
// ══════════════════════════════════════════════════════════
if (require.main === module) {
const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const stepIdx = args.indexOf('--step');
const step = stepIdx >= 0 && args[stepIdx + 1] ? args[stepIdx + 1] : null;
const personaIdx = args.indexOf('--persona');
const persona = personaIdx >= 0 && args[personaIdx + 1] ? args[personaIdx + 1] : 'zhuyuan';
const taskIdx = args.indexOf('--task');
const task = taskIdx >= 0 && args[taskIdx + 1] ? args[taskIdx + 1] : null;
runLoop({ dryRun, step, persona, task }).then(result => {
if (!result.success) {
process.exit(1);
}
}).catch(err => {
console.error('[OPENCLAW] 💥 致命错误:', err.message);
process.exit(1);
});
}