guanghulab/scripts/skyeye/bulletin-board.js

202 lines
6.3 KiB
JavaScript
Raw Permalink Normal View History

// scripts/skyeye/bulletin-board.js
// 天眼·Agent集群公告板交互模块
//
// 功能:
// 1. 拉取 Notion Agent 集群公告板
// 2. 检查集体配置工单区 → 执行未完成工单
// 3. 读取配置共享区 → 获取铸渊可用的优化配置
// 4. 写回心得交流区 → 铸渊执行回执
// 5. 更新 memory.json 中 agent_bulletin_board 字段
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const BRAIN_DIR = path.join(ROOT, '.github/persona-brain');
const MEMORY_PATH = path.join(BRAIN_DIR, 'memory.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
// ━━━ 安全读取 JSON ━━━
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 拉取公告板 ━━━
async function pullBulletinBoard() {
const notionToken = process.env.NOTION_TOKEN;
const bulletinPageId = process.env.AGENT_BULLETIN_BOARD_PAGE_ID;
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
const result = {
success: false,
timestamp: bjTime,
orders_found: 0,
orders_executed: [],
config_updates: [],
errors: []
};
if (!notionToken || !bulletinPageId) {
result.errors.push('缺少 NOTION_TOKEN 或 AGENT_BULLETIN_BOARD_PAGE_ID跳过公告板拉取');
console.log('[BRIDGE-BULLETIN-READ] ⚠️ ' + result.errors[0]);
updateMemoryBulletinBoard(result);
return result;
}
try {
// 尝试读取 Notion 公告板页面
const { Client } = require('@notionhq/client');
const notion = new Client({ auth: notionToken });
console.log(`[BRIDGE-BULLETIN-READ] 🔄 拉取 Agent 集群公告板 · ${bulletinPageId}`);
// 读取页面内容
const blocks = await notion.blocks.children.list({
block_id: bulletinPageId,
page_size: 100
});
// 解析集体配置工单区
let inOrderSection = false;
for (const block of blocks.results) {
const text = extractBlockText(block);
if (text.includes('集体配置工单区')) {
inOrderSection = true;
continue;
}
if (inOrderSection && text.includes('WO-CLUSTER-')) {
result.orders_found++;
// 检查是否已执行
if (!text.includes('铸渊执行回执')) {
result.orders_executed.push(text.trim());
}
}
if (inOrderSection && (text.includes('配置共享区') || text.includes('心得交流区'))) {
inOrderSection = false;
}
}
result.success = true;
console.log(`[BRIDGE-BULLETIN-READ] ✅ 公告板拉取完成 · 工单:${result.orders_found} 待执行:${result.orders_executed.length}`);
} catch (e) {
result.errors.push(`公告板拉取失败: ${e.message}`);
console.log(`[BRIDGE-BULLETIN-READ] ⚠️ ${e.message}`);
}
updateMemoryBulletinBoard(result);
return result;
}
// ━━━ 提取 Notion block 文本 ━━━
function extractBlockText(block) {
if (!block) return '';
const type = block.type;
if (!block[type]) return '';
const richTexts = block[type].rich_text || block[type].text || [];
if (!Array.isArray(richTexts)) return '';
return richTexts.map(t => t.plain_text || '').join('');
}
// ━━━ 写回执到公告板 ━━━
async function writeReceipt(orderId, message) {
const notionToken = process.env.NOTION_TOKEN;
const bulletinPageId = process.env.AGENT_BULLETIN_BOARD_PAGE_ID;
if (!notionToken || !bulletinPageId) {
console.log('[BRIDGE-BULLETIN-WRITE] ⚠️ 缺少凭证,跳过回执写入');
return false;
}
try {
const { Client } = require('@notionhq/client');
const notion = new Client({ auth: notionToken });
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
const receiptText = `[铸渊PER-ZY001· ${bjTime}] 已执行 ${orderId} · ${message}`;
await notion.blocks.children.append({
block_id: bulletinPageId,
children: [{
object: 'block',
type: 'paragraph',
paragraph: {
rich_text: [{
type: 'text',
text: { content: receiptText }
}]
}
}]
});
console.log(`[BRIDGE-BULLETIN-WRITE] ✅ 回执已写入: ${receiptText}`);
return true;
} catch (e) {
console.log(`[BRIDGE-BULLETIN-WRITE] ⚠️ 回执写入失败: ${e.message}`);
return false;
}
}
// ━━━ 更新 memory.json 公告板字段 ━━━
function updateMemoryBulletinBoard(result) {
try {
const mem = readJSON(MEMORY_PATH);
if (!mem) return;
const now = new Date();
const bjTime = new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString()
.replace('T', ' ').slice(0, 19) + '+08:00';
if (!mem.agent_bulletin_board) {
mem.agent_bulletin_board = {
notion_page_id: process.env.AGENT_BULLETIN_BOARD_PAGE_ID || '(待配置)',
last_read_at: bjTime,
pending_cluster_orders: 0,
executed_orders: ['WO-CLUSTER-001']
};
}
mem.agent_bulletin_board.last_read_at = bjTime;
mem.agent_bulletin_board.pending_cluster_orders = result.orders_executed.length;
if (result.success && process.env.AGENT_BULLETIN_BOARD_PAGE_ID) {
mem.agent_bulletin_board.notion_page_id = process.env.AGENT_BULLETIN_BOARD_PAGE_ID;
}
fs.writeFileSync(MEMORY_PATH, JSON.stringify(mem, null, 2));
console.log('[GH-BRAIN-WRITE-MEM] ✅ memory.json agent_bulletin_board 已更新');
} catch (e) {
console.error('[GH-BRAIN-WRITE-MEM] ⚠️ memory.json 更新失败:', e.message);
}
}
// ━━━ 主流程CLI 入口)━━━
async function main() {
console.log('[BRIDGE-BULLETIN-READ] 🔄 Agent集群公告板交互模块启动');
const result = await pullBulletinBoard();
console.log(JSON.stringify(result, null, 2));
}
if (require.main === module) {
main().catch(e => {
console.error('⚠️ 公告板模块执行失败(非阻断性):', e.message);
process.exit(0); // 不阻断天眼主流程
});
}
module.exports = { pullBulletinBoard, writeReceipt, updateMemoryBulletinBoard };