336 lines
9.1 KiB
JavaScript
Raw Permalink Normal View History

/**
* core/system-check 仓库自检系统
*
* 功能
* - 扫描仓库结构完整性
* - 检查自动化工作流状态
* - 检测配置错误
* - 更新系统索引
*
* 执行周期daily cron通过 daily-maintenance 工作流触发
*
* 调用方式
* node core/system-check
*/
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
/**
* 必需目录列表
*/
const REQUIRED_DIRS = [
'brain',
'src',
'scripts',
'core/broadcast-listener',
'core/task-queue',
'core/system-check',
'core/execution-sync',
'core/context-loader',
'core/brain-wake',
'connectors/notion-sync',
'connectors/notion-wake-listener',
'connectors/model-router',
'.github/workflows',
'docs'
];
/**
* 必需文件列表
*/
const REQUIRED_FILES = [
'brain/master-brain.md',
'brain/read-order.md',
'brain/repo-map.json',
'brain/system-health.json',
'brain/id-map.json',
'package.json',
'ecosystem.config.js',
'docs/repo-structure-map.md',
'docs/notion-bridge-map.md'
];
/**
* 检查目录是否存在
*/
function checkDirectories() {
console.log('\n📂 目录结构检查:');
const results = [];
for (const dir of REQUIRED_DIRS) {
const fullPath = path.join(ROOT, dir);
const exists = fs.existsSync(fullPath);
const icon = exists ? '✅' : '❌';
console.log(` ${icon} ${dir}`);
results.push({ path: dir, exists, type: 'directory' });
}
return results;
}
/**
* 检查必需文件
*/
function checkFiles() {
console.log('\n📄 必需文件检查:');
const results = [];
for (const file of REQUIRED_FILES) {
const fullPath = path.join(ROOT, file);
const exists = fs.existsSync(fullPath);
const icon = exists ? '✅' : '❌';
console.log(` ${icon} ${file}`);
results.push({ path: file, exists, type: 'file' });
}
return results;
}
/**
* 检查工作流数量
*/
function checkWorkflows() {
console.log('\n⚙ 工作流检查:');
const workflowDir = path.join(ROOT, '.github/workflows');
if (!fs.existsSync(workflowDir)) {
console.log(' ❌ 工作流目录不存在');
return { count: 0, files: [] };
}
const files = fs.readdirSync(workflowDir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
console.log(` ✅ 发现 ${files.length} 个工作流文件`);
return { count: files.length, files };
}
/**
* 检查核心模块状态
*/
function checkCoreModules() {
console.log('\n🔧 核心模块检查:');
const modules = [
{ name: 'broadcast-listener', path: 'core/broadcast-listener/index.js' },
{ name: 'task-queue', path: 'core/task-queue/index.js' },
{ name: 'system-check', path: 'core/system-check/index.js' },
{ name: 'execution-sync', path: 'core/execution-sync/index.js' },
{ name: 'context-loader', path: 'core/context-loader/index.js' },
{ name: 'brain-wake', path: 'core/brain-wake/index.js' },
{ name: 'notion-sync', path: 'connectors/notion-sync/index.js' },
{ name: 'notion-wake-listener', path: 'connectors/notion-wake-listener/index.js' },
{ name: 'model-router', path: 'connectors/model-router/index.js' }
];
const results = [];
for (const mod of modules) {
const fullPath = path.join(ROOT, mod.path);
const exists = fs.existsSync(fullPath);
const icon = exists ? '✅' : '❌';
console.log(` ${icon} ${mod.name}${mod.path}`);
results.push({ ...mod, exists });
}
return results;
}
/**
* 检查 JSON 文件完整性
*/
function checkJsonIntegrity() {
console.log('\n🔍 JSON 完整性检查:');
const jsonFiles = [
'brain/repo-map.json',
'brain/system-health.json',
'brain/id-map.json',
'package.json'
];
const results = [];
for (const file of jsonFiles) {
const fullPath = path.join(ROOT, file);
if (!fs.existsSync(fullPath)) {
console.log(` ⏭️ ${file} — 文件不存在`);
results.push({ path: file, valid: false, reason: 'missing' });
continue;
}
try {
JSON.parse(fs.readFileSync(fullPath, 'utf-8'));
console.log(`${file}`);
results.push({ path: file, valid: true });
} catch (e) {
console.log(`${file} — JSON 解析错误`);
results.push({ path: file, valid: false, reason: 'parse_error' });
}
}
return results;
}
/**
* 生成自检报告
*/
function generateReport(dirResults, fileResults, workflows, modules, jsonResults) {
const totalChecks = dirResults.length + fileResults.length + modules.length + jsonResults.length;
const passed = [
...dirResults.filter(r => r.exists),
...fileResults.filter(r => r.exists),
...modules.filter(r => r.exists),
...jsonResults.filter(r => r.valid)
].length;
const report = {
version: '5.1',
checked_at: new Date().toISOString(),
summary: {
total_checks: totalChecks,
passed: passed,
failed: totalChecks - passed,
health_score: Math.round((passed / totalChecks) * 100)
},
workflows: {
count: workflows.count
},
directories: dirResults,
files: fileResults,
modules: modules,
json_integrity: jsonResults
};
return report;
}
/**
* 根据自检结果生成自动任务
*/
function generateAutoTasks(report) {
const tasks = [];
const timestamp = new Date().toISOString();
// 检查目录缺失 → 生成修复任务
const missingDirs = (report.directories || []).filter(d => !d.exists);
for (const dir of missingDirs) {
tasks.push({
task_id: `auto-fix-dir-${dir.path.replace(/\//g, '-')}-${timestamp.slice(0, 10)}`,
type: 'auto-task',
source: 'system-check',
priority: 'high',
status: 'pending',
executor: 'zhuyuan',
description: `修复缺失目录: ${dir.path}`
});
}
// 检查文件缺失 → 生成修复任务
const missingFiles = (report.files || []).filter(f => !f.exists);
for (const file of missingFiles) {
tasks.push({
task_id: `auto-fix-file-${file.path.replace(/\//g, '-')}-${timestamp.slice(0, 10)}`,
type: 'auto-task',
source: 'system-check',
priority: 'high',
status: 'pending',
executor: 'zhuyuan',
description: `修复缺失文件: ${file.path}`
});
}
// 检查模块缺失 → 生成修复任务
const missingModules = (report.modules || []).filter(m => !m.exists);
for (const mod of missingModules) {
tasks.push({
task_id: `auto-fix-module-${mod.name}-${timestamp.slice(0, 10)}`,
type: 'auto-task',
source: 'system-check',
priority: 'normal',
status: 'pending',
executor: 'zhuyuan',
description: `修复缺失模块: ${mod.name}`
});
}
// JSON 完整性失败 → 生成修复任务
const invalidJson = (report.json_integrity || []).filter(j => !j.valid);
for (const json of invalidJson) {
tasks.push({
task_id: `auto-fix-json-${json.path.replace(/\//g, '-')}-${timestamp.slice(0, 10)}`,
type: 'auto-task',
source: 'system-check',
priority: 'high',
status: 'pending',
executor: 'zhuyuan',
description: `修复 JSON 文件: ${json.path} (${json.reason})`
});
}
// 健康分数低 → 生成结构优化任务
if (report.summary && report.summary.health_score < 100) {
tasks.push({
task_id: `auto-optimize-structure-${timestamp.slice(0, 10)}`,
type: 'maintenance-task',
source: 'system-check',
priority: 'low',
status: 'pending',
executor: 'zhuyuan',
description: `结构优化: 健康分数 ${report.summary.health_score}%`
});
}
return tasks;
}
/**
* 主执行函数
*/
function run() {
console.log('🏥 铸渊仓库自检系统 v5.1');
console.log('═'.repeat(40));
const dirResults = checkDirectories();
const fileResults = checkFiles();
const workflows = checkWorkflows();
const modules = checkCoreModules();
const jsonResults = checkJsonIntegrity();
const report = generateReport(dirResults, fileResults, workflows, modules, jsonResults);
console.log('\n═'.repeat(40));
console.log(`📊 自检报告: ${report.summary.passed}/${report.summary.total_checks} 通过 (${report.summary.health_score}%)`);
if (report.summary.failed > 0) {
console.log(`⚠️ 发现 ${report.summary.failed} 项问题`);
} else {
console.log('✅ 系统状态健康');
}
return report;
}
// CLI 入口
if (require.main === module) {
const report = run();
// 可选:输出 JSON 报告
if (process.argv.includes('--json')) {
const reportPath = path.join(ROOT, 'core/system-check/last-report.json');
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
console.log(`\n📝 报告已保存: ${reportPath}`);
}
// 可选:生成自动任务
if (process.argv.includes('--auto-tasks')) {
const autoTasks = generateAutoTasks(report);
if (autoTasks.length > 0) {
console.log(`\n🔄 生成 ${autoTasks.length} 个自动任务:`);
autoTasks.forEach(t => console.log(` 📋 ${t.task_id}: ${t.description}`));
} else {
console.log('\n✅ 系统健康,无需生成自动任务');
}
}
}
module.exports = { run, generateAutoTasks, checkDirectories, checkFiles, checkWorkflows, checkCoreModules, checkJsonIntegrity };