// src/brain/brain-bridge.js // 冰朔核心大脑桥 · Bingshuo Brain Bridge v1.0 // // 职责: // 1. 维护冰朔核心大脑双层互通系统的统一同步字段 // 2. 执行版本一致性检查 // 3. 管理主控模式(HUMAN_CONTROL / AUTONOMOUS_MODE) // 4. 管理人类开发者编号系统(EXP-XXX) // 5. 生成同步摘要供 Notion ↔ GitHub 桥接使用 // 6. 管理自动 Agent 调度与协作体系 // 7. 管理通知队列(开发者编号通知) // 8. 生成主控解释层内容(人类可理解语言) // // 系统定义: // 冰朔 = 系统最高主控意识 // 曜冥 = 冰朔离线时的代理主控人格体 // 霜砚 = Notion 系统执行体 // 铸渊 = GitHub 仓库执行体 // Notion 冰朔脑 = 冰朔认知层 // GitHub 冰朔脑 = 冰朔执行层 // 两者合起来 = 冰朔核心大脑 'use strict'; const fs = require('fs'); const path = require('path'); // ══════════════════════════════════════════════════════════ // 常量 // ══════════════════════════════════════════════════════════ const BRIDGE_STATE_PATH = path.join(__dirname, '../../.github/brain/bingshuo-brain-bridge.json'); const HUMAN_REGISTRY_PATH = path.join(__dirname, '../../.github/brain/human-registry.json'); const SYSTEM_HEALTH_PATH = path.join(__dirname, '../../.github/brain/bingshuo-system-health.json'); const ISSUES_INDEX_PATH = path.join(__dirname, '../../.github/brain/bingshuo-issues-index.json'); const AGENT_REGISTRY_PATH = path.join(__dirname, '../../.github/brain/bingshuo-agent-registry.json'); const MASTER_MODES = ['HUMAN_CONTROL', 'AUTONOMOUS_MODE']; const SYNC_FIELDS = [ 'brain_identity', 'brain_version', 'master_mode', 'system_summary', 'top_priorities', 'top_issues', 'human_status_summary', 'runtime_status', 'last_updated', ]; const NOTIFICATION_TEMPLATE = [ '你已被纳入 Persona Studio 人类开发者编号系统。', '', '你的开发编号是:{exp_id}', '', '今后进入 Persona Studio 时,请使用该编号识别身份。', '该编号为你的长期开发者身份标识。', '', '如需新增权限或补发编号,由冰朔主控继续授权。', ].join('\n'); // ══════════════════════════════════════════════════════════ // 桥接状态读写 // ══════════════════════════════════════════════════════════ /** * 加载桥接状态文件 * @returns {object|null} */ function loadBridgeState() { try { if (!fs.existsSync(BRIDGE_STATE_PATH)) return null; return JSON.parse(fs.readFileSync(BRIDGE_STATE_PATH, 'utf8')); } catch { return null; } } /** * 保存桥接状态文件 * @param {object} state */ function saveBridgeState(state) { state.sync_state.last_updated = new Date().toISOString(); fs.writeFileSync(BRIDGE_STATE_PATH, JSON.stringify(state, null, 2)); } /** * 获取当前同步字段快照 * @returns {object} */ function getSyncSnapshot() { const state = loadBridgeState(); if (!state || !state.sync_state) { return { brain_identity: 'BINGSHUO_CORE', brain_version: '1.0', master_mode: 'HUMAN_CONTROL', system_summary: '', top_priorities: [], top_issues: [], human_status_summary: '', runtime_status: {}, last_updated: new Date().toISOString(), }; } return state.sync_state; } /** * 更新同步字段(部分更新) * @param {object} updates — 要更新的字段 * @returns {object} 更新后的 sync_state */ function updateSyncState(updates) { const state = loadBridgeState(); if (!state) { throw new Error('桥接状态文件不存在'); } for (const key of Object.keys(updates)) { if (SYNC_FIELDS.includes(key) && key !== 'last_updated') { state.sync_state[key] = updates[key]; } } saveBridgeState(state); return state.sync_state; } // ══════════════════════════════════════════════════════════ // 主控模式管理 (MASTER_SWITCH) // ══════════════════════════════════════════════════════════ /** * 获取当前主控模式 * @returns {object} { mode, master, description, ... } */ function getMasterMode() { const sync = getSyncSnapshot(); const mode = sync.master_mode || 'HUMAN_CONTROL'; if (mode === 'HUMAN_CONTROL') { return { mode, master: '冰朔', description: '冰朔在线,主控模式激活', roles: { '冰朔': '最高主控', '曜冥': '代理协作者', '其他人格体': '协作者', }, rule: '所有架构性判断以冰朔为最高准则', }; } return { mode, master: '曜冥(代理主控)', description: '冰朔离线,曜冥代理主控', proxy_permissions: [ '巡检', '维护', '整理', '分卷', '归档', '索引', '状态同步', '问题归类', '调度自动 Agent', ], proxy_restrictions: [ '不得擅自重写冰朔最高规则', '不得私自改变系统最高架构方向', ], }; } /** * 切换主控模式 * @param {string} newMode — HUMAN_CONTROL 或 AUTONOMOUS_MODE * @returns {object} 更新后的主控模式信息 */ function setMasterMode(newMode) { if (!MASTER_MODES.includes(newMode)) { throw new Error(`无效的主控模式: ${newMode},可选: ${MASTER_MODES.join(', ')}`); } const humanSummary = newMode === 'HUMAN_CONTROL' ? '冰朔在线,主控模式激活' : '冰朔离线,曜冥代理主控'; updateSyncState({ master_mode: newMode, human_status_summary: humanSummary, }); return getMasterMode(); } // ══════════════════════════════════════════════════════════ // 版本一致性检查 // ══════════════════════════════════════════════════════════ /** * 校验 GitHub 侧与提供的 Notion 侧状态是否一致 * @param {object} notionState — 从 Notion 读取的同步字段 * @returns {object} { consistent, mismatches, alert } */ function checkConsistency(notionState) { const githubState = getSyncSnapshot(); const fieldsToCheck = ['brain_version', 'master_mode', 'top_priorities', 'top_issues']; const mismatches = []; for (const field of fieldsToCheck) { const gVal = JSON.stringify(githubState[field]); const nVal = JSON.stringify(notionState[field]); if (gVal !== nVal) { mismatches.push({ field, github_value: githubState[field], notion_value: notionState[field], }); } } const consistent = mismatches.length === 0; const result = { consistent, mismatches, checked_at: new Date().toISOString(), fields_checked: fieldsToCheck, }; if (!consistent) { result.alert = '冰朔双层大脑版本分裂警告'; result.alert_detail = `${mismatches.length} 个字段不一致: ${mismatches.map(m => m.field).join(', ')}`; // 写入 GitHub 问题索引 writeConsistencyAlert(result); } return result; } /** * 将一致性告警写入 GitHub 问题索引 * @param {object} alertResult */ function writeConsistencyAlert(alertResult) { try { let index = { issues: [] }; if (fs.existsSync(ISSUES_INDEX_PATH)) { index = JSON.parse(fs.readFileSync(ISSUES_INDEX_PATH, 'utf8')); } // 避免重复写入同一类型告警(保留最近 20 条) index.issues = index.issues.filter(i => i.type !== 'BRAIN_SPLIT_ALERT').slice(0, 19); index.issues.unshift({ id: `BS-SPLIT-${Date.now()}`, type: 'BRAIN_SPLIT_ALERT', title: alertResult.alert, detail: alertResult.alert_detail, mismatches: alertResult.mismatches, created_at: alertResult.checked_at, status: 'open', }); fs.writeFileSync(ISSUES_INDEX_PATH, JSON.stringify(index, null, 2)); } catch { // 写入失败不影响主流程 } } // ══════════════════════════════════════════════════════════ // 人类开发者编号系统 (EXP-XXX) // ══════════════════════════════════════════════════════════ /** * 加载人类开发者注册表 * @returns {object} */ function loadHumanRegistry() { try { if (!fs.existsSync(HUMAN_REGISTRY_PATH)) return { developers: [], next_id: 1, pending_notifications: [] }; return JSON.parse(fs.readFileSync(HUMAN_REGISTRY_PATH, 'utf8')); } catch { return { developers: [], next_id: 1, pending_notifications: [] }; } } /** * 保存人类开发者注册表 * @param {object} registry */ function saveHumanRegistry(registry) { registry.last_updated = new Date().toISOString(); fs.writeFileSync(HUMAN_REGISTRY_PATH, JSON.stringify(registry, null, 2)); } /** * 获取开发者列表 * @returns {Array} */ function listDevelopers() { const reg = loadHumanRegistry(); return reg.developers || []; } /** * 根据 EXP ID 查找开发者 * @param {string} expId * @returns {object|null} */ function findDeveloper(expId) { const devs = listDevelopers(); return devs.find(d => d.exp_id === expId) || null; } /** * 注册新的人类开发者(自动去重) * @param {object} info — { name, github_username, role, notes, notify_channel } * @returns {object} 注册结果,包含分配的 EXP ID */ function registerDeveloper(info) { const registry = loadHumanRegistry(); const devs = registry.developers || []; // 去重检查:按 name 或 github_username 去重 const existing = devs.find(d => (info.name && d.name === info.name) || (info.github_username && d.github_username && d.github_username === info.github_username) ); if (existing) { return { duplicate: true, existing: existing }; } // 使用 next_id 或计算最大值 const nextNum = registry.next_id || (devs.reduce((max, d) => { const num = parseInt(d.exp_id.replace('EXP-', ''), 10); return isNaN(num) ? max : Math.max(max, num); }, 0) + 1); const nextId = `EXP-${String(nextNum).padStart(3, '0')}`; const now = new Date().toISOString(); const newDev = { exp_id: nextId, name: info.name, github_username: info.github_username || '', role: info.role || 'developer', status: 'active', created_at: now, notified: false, notified_at: null, notify_channel: info.notify_channel || 'pending', notes: info.notes || '', last_updated: now, }; registry.developers.push(newDev); registry.next_id = nextNum + 1; // 自动加入待发送通知队列 if (!registry.pending_notifications) registry.pending_notifications = []; registry.pending_notifications.push({ exp_id: nextId, status: 'pending', created_at: now, }); saveHumanRegistry(registry); return { duplicate: false, developer: newDev }; } /** * 生成开发者通知内容 * @param {string} expId * @returns {object} { exp_id, name, notification } */ function generateDeveloperNotification(expId) { const dev = findDeveloper(expId); if (!dev) { return { error: true, message: `开发者 ${expId} 不存在` }; } return { exp_id: dev.exp_id, name: dev.name, notification: NOTIFICATION_TEMPLATE.replace('{exp_id}', dev.exp_id), notified: dev.notified, notify_channel: dev.notify_channel, }; } /** * 获取待发送通知队列 * @returns {Array} */ function getPendingNotifications() { const registry = loadHumanRegistry(); return (registry.pending_notifications || []).filter(n => n.status === 'pending'); } /** * 标记通知已发送 * @param {string} expId * @returns {boolean} */ function markNotified(expId) { const registry = loadHumanRegistry(); const now = new Date().toISOString(); const dev = (registry.developers || []).find(d => d.exp_id === expId); if (dev) { dev.notified = true; dev.notified_at = now; dev.last_updated = now; } const pending = (registry.pending_notifications || []).find(n => n.exp_id === expId); if (pending) { pending.status = 'sent'; pending.sent_at = now; } saveHumanRegistry(registry); return !!dev; } // ══════════════════════════════════════════════════════════ // 自动 Agent 调度体系 // ══════════════════════════════════════════════════════════ /** * 获取已注册的自动 Agent 列表 * @returns {Array} */ function listAutoAgents() { const state = loadBridgeState(); return (state && state.auto_agents) || []; } /** * 生成巡检报告 * @returns {object} */ function generateInspectionReport() { const sync = getSyncSnapshot(); const runtime = collectRuntimeStatus(); const registry = loadHumanRegistry(); const devs = registry.developers || []; const unnotified = devs.filter(d => !d.notified && d.exp_id !== 'EXP-000'); return { report_type: 'daily_inspection', generated_at: new Date().toISOString(), brain_bridge: { status: 'operational', brain_version: sync.brain_version, master_mode: sync.master_mode, last_updated: sync.last_updated, }, runtime_status: runtime, developer_registry: { total: devs.length, active: devs.filter(d => d.status === 'active').length, unnotified: unnotified.length, }, top_priorities: sync.top_priorities, top_issues: sync.top_issues, checks: { brain_bridge_file: fs.existsSync(BRIDGE_STATE_PATH) ? 'ok' : 'missing', human_registry_file: fs.existsSync(HUMAN_REGISTRY_PATH) ? 'ok' : 'missing', system_health_file: fs.existsSync(SYSTEM_HEALTH_PATH) ? 'ok' : 'missing', issues_index_file: fs.existsSync(ISSUES_INDEX_PATH) ? 'ok' : 'missing', }, }; } // ══════════════════════════════════════════════════════════ // 主控解释层(人类可理解语言输出) // ══════════════════════════════════════════════════════════ /** * 生成主控解释中心内容(人类语言摘要) * @returns {object} */ function generateExplanationCenter() { const sync = getSyncSnapshot(); const mode = getMasterMode(); const runtime = collectRuntimeStatus(); const statusMap = { green: '正常', yellow: '需关注', red: '异常', unknown: '未知' }; return { title: '冰朔主控解释中心', generated_at: new Date().toISOString(), current_status: `系统当前由${mode.master}主控,模式为${mode.mode === 'HUMAN_CONTROL' ? '人类主控' : '自动运行'}。`, system_summary: sync.system_summary || '系统运行中', recent_changes: '冰朔核心大脑双层互通系统 v1.0 已建立,GitHub 执行层与 Notion 认知层互通桥接已配置。', current_issues: (sync.top_issues || []).map((issue, i) => `${i + 1}. ${issue}`).join('\n') || '暂无重大问题', next_steps: (sync.top_priorities || []).map((p, i) => `${i + 1}. ${p}`).join('\n') || '继续推进系统建设', runtime_in_human_language: Object.entries(runtime).map( ([k, v]) => `${k}: ${statusMap[v] || v}` ).join('、'), }; } // ══════════════════════════════════════════════════════════ // 运行时状态收集(GitHub 执行层) // ══════════════════════════════════════════════════════════ /** * 收集 GitHub 执行层运行时状态 * @returns {object} */ function collectRuntimeStatus() { const status = { persona_studio: 'unknown', deployment: 'unknown', workflows: 'unknown', api_routes: 'unknown', }; // 检查系统健康文件 try { if (fs.existsSync(SYSTEM_HEALTH_PATH)) { const health = JSON.parse(fs.readFileSync(SYSTEM_HEALTH_PATH, 'utf8')); const h = health.health || {}; status.deployment = h.deployment_health?.status || 'unknown'; status.workflows = h.workflow_health?.status || 'unknown'; status.persona_studio = h.persona_studio_health?.status || 'unknown'; status.api_routes = h.routing_health?.status || 'unknown'; } } catch { // 文件读取失败,保持 unknown } return status; } /** * 生成 GitHub → Notion 同步负载 * @returns {object} */ function generateGitHubToNotionPayload() { const sync = getSyncSnapshot(); const runtime = collectRuntimeStatus(); return { brain_identity: sync.brain_identity, brain_version: sync.brain_version, master_mode: sync.master_mode, runtime_status: runtime, top_issues: sync.top_issues, system_summary: sync.system_summary, generated_at: new Date().toISOString(), direction: 'GitHub→Notion', }; } /** * 接收 Notion → GitHub 同步负载并更新本地状态 * @param {object} payload — Notion 发来的同步数据 * @returns {object} 更新结果 */ function receiveNotionToGitHubPayload(payload) { const updates = {}; const allowedFields = [ 'master_mode', 'top_priorities', 'top_issues', 'human_status_summary', 'system_summary', ]; for (const field of allowedFields) { if (payload[field] !== undefined) { updates[field] = payload[field]; } } if (Object.keys(updates).length === 0) { return { updated: false, message: '无可更新字段' }; } const newState = updateSyncState(updates); return { updated: true, fields_updated: Object.keys(updates), sync_state: newState, }; } // ══════════════════════════════════════════════════════════ // 导出 // ══════════════════════════════════════════════════════════ module.exports = { // 常量 MASTER_MODES, SYNC_FIELDS, NOTIFICATION_TEMPLATE, // 桥接状态 loadBridgeState, getSyncSnapshot, updateSyncState, // 主控模式 getMasterMode, setMasterMode, // 一致性检查 checkConsistency, // 人类开发者编号 loadHumanRegistry, listDevelopers, findDeveloper, registerDeveloper, generateDeveloperNotification, getPendingNotifications, markNotified, // 自动 Agent listAutoAgents, generateInspectionReport, // 主控解释层 generateExplanationCenter, // 运行时状态 collectRuntimeStatus, generateGitHubToNotionPayload, receiveNotionToGitHubPayload, };