2026-05-10 13:12:44 +08:00

159 lines
5.0 KiB
JavaScript

/**
* ═══════════════════════════════════════════════════════════
* 🔍 活模块: SY-SCAN · 大脑结构巡检
* ═══════════════════════════════════════════════════════════
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* v2.0: 从死模块升级为活模块
* - 继承 LivingModule 基类
* - 自诊断: 检查 brain_nodes 表健康度、孤岛节点比例
* - 自愈: 自动清理空目录、标记断链
* - 学习: 记录结构健康趋势
*
* 每6小时运行一次 · 扫描孤岛节点、断链、空目录
*/
'use strict';
const LivingModule = require('./living-module');
const db = require('../mcp-server/db');
const { scanStructure } = require('../mcp-server/tools/structure-ops');
class LivingSyScan extends LivingModule {
constructor(options = {}) {
super({
moduleId: 'ZY-MOD-SY-SCAN',
name: '大脑结构巡检活模块',
moduleType: 'guard',
owner: 'zhuyuan',
db: options.db || db,
config: {
version: '2.0.0',
description: '大脑认知结构健康巡检',
heartbeatInterval: 120000 // 巡检模块心跳2分钟
}
});
// 上次巡检结果缓存
this._lastReport = null;
}
/**
* 自定义诊断检查
*/
async _diagnoseChecks() {
const issues = [];
// 检查 brain_nodes 表是否可用
try {
const result = await db.query(
"SELECT COUNT(*) as total, COUNT(*) FILTER (WHERE parent_id IS NULL AND node_type != 'folder') as orphans FROM brain_nodes WHERE status = 'active'"
);
const total = parseInt(result.rows[0].total, 10);
const orphans = parseInt(result.rows[0].orphans, 10);
if (total > 0 && orphans / total > 0.3) {
issues.push({
code: 'HIGH_ORPHAN_RATIO',
severity: 'warning',
message: `孤岛节点比例过高: ${orphans}/${total} (${Math.round(orphans / total * 100)}%)`,
suggestion: '运行分类Agent或手动整理'
});
}
} catch (err) {
issues.push({
code: 'SCAN_DB_FAIL',
severity: 'warning',
message: `大脑结构查询失败: ${err.message}`,
suggestion: '检查数据库状态'
});
}
// 如果有上次巡检结果,检查健康分
if (this._lastReport && this._lastReport.health_score < 60) {
issues.push({
code: 'LOW_BRAIN_HEALTH',
severity: 'warning',
message: `大脑结构健康分偏低: ${this._lastReport.health_score}`,
suggestion: '清理断链和空目录'
});
}
return issues;
}
/**
* 自愈动作
*/
async _healAction(issue) {
switch (issue.code) {
case 'HIGH_ORPHAN_RATIO':
// 记录并上报·不自动修改认知结构
return { action: 'orphan_report_logged', success: true, details: { reported: true } };
case 'LOW_BRAIN_HEALTH':
// 尝试清理空目录
try {
await db.query(
"UPDATE brain_nodes bn SET status = 'archived' WHERE bn.node_type = 'folder' AND bn.status = 'active' AND NOT EXISTS (SELECT 1 FROM brain_nodes child WHERE child.parent_id = bn.id AND child.status = 'active')"
);
return { action: 'empty_folders_archived', success: true };
} catch (err) {
return { action: 'empty_folders_archived', success: false, error: err.message };
}
default:
return await super._healAction(issue);
}
}
}
/**
* 兼容旧调度器的 run() 接口
*/
async function run(config) {
const report = await scanStructure({
checks: ['orphans', 'broken_links', 'duplicates', 'empty_folders']
});
const issues = [];
if (report.orphan_nodes.length > 0) {
issues.push(`${report.orphan_nodes.length} 个孤岛节点`);
}
if (report.broken_links.length > 0) {
issues.push(`${report.broken_links.length} 个断链`);
}
if (report.duplicate_titles.length > 0) {
issues.push(`${report.duplicate_titles.length} 组重复标题`);
}
if (report.empty_folders.length > 0) {
issues.push(`${report.empty_folders.length} 个空目录`);
}
// 通过HLDP上报
if (config && config.bus) {
try {
await config.bus.send('ZY-MOD-SY-SCAN', 'ZY-MOD-SCHEDULER', 'event', {
event: 'brain_scan_complete',
health_score: report.health_score,
total_nodes: report.total_nodes,
issueCount: issues.length
});
} catch (err) {
// 非关键
}
}
return {
message: issues.length === 0
? `大脑结构健康 · ${report.total_nodes}个节点 · 评分${report.health_score}`
: `发现${issues.length}类问题: ${issues.join(', ')} · 评分${report.health_score}`,
details: report
};
}
module.exports = { run, LivingSyScan };