guanghulab/scripts/generate-session-summary.js
2026-05-10 13:12:44 +08:00

146 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
// scripts/generate-session-summary.js
// 铸渊 · 会话摘要生成器
//
// 在 Notion Agent 巡检前 10 分钟自动运行,生成 latest-summary.json
// 供 Notion 侧「铸渊·桥接巡检引擎」读取
//
// 用法node scripts/generate-session-summary.js
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const TELEMETRY_DIR = path.join(ROOT, 'persona-telemetry');
const SUMMARY_FILE = path.join(TELEMETRY_DIR, 'latest-summary.json');
const SYSLOG_INBOX = path.join(ROOT, 'syslog-inbox');
const DEV_STATUS = path.join(ROOT, '.github', 'persona-brain', 'dev-status.json');
const STYLE_CONFIG = path.join(ROOT, '.github', 'persona-brain', 'style-config.json');
const MEMORY_FILE = path.join(ROOT, '.github', 'persona-brain', 'memory.json');
const TUNING_QUEUE = path.join(TELEMETRY_DIR, 'tuning-queue');
// ══════════════════════════════════════════════════════════
// 辅助函数
// ══════════════════════════════════════════════════════════
function safeReadJSON(filePath) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch {
return null;
}
}
function countFiles(dir, ext) {
if (!fs.existsSync(dir)) return 0;
return fs.readdirSync(dir).filter(f => {
if (ext) return f.endsWith(ext);
return !f.startsWith('.') && f !== 'README.md';
}).length;
}
function countPendingTuningOrders() {
if (!fs.existsSync(TUNING_QUEUE)) return 0;
return fs.readdirSync(TUNING_QUEUE).filter(f =>
f.startsWith('TUNE-') && f.endsWith('.json')
).length;
}
// ══════════════════════════════════════════════════════════
// 主流程
// ══════════════════════════════════════════════════════════
function generateSummary() {
const now = new Date().toISOString();
// 读取开发者状态
const devStatus = safeReadJSON(DEV_STATUS);
const activeDevs = devStatus?.team_status
?.filter(d => d.status && d.status.includes('🟢'))
.map(d => d.dev_id) || [];
// 读取记忆文件
const memory = safeReadJSON(MEMORY_FILE);
// 读取风格配置
const styleConfig = safeReadJSON(STYLE_CONFIG);
// 统计未处理 SYSLOG
const syslogCount = countFiles(SYSLOG_INBOX, '.json');
// 统计待处理微调工单
const pendingOrders = countPendingTuningOrders();
// 构建摘要
const summary = {
version: '1.0',
timestamp: now,
sessions: {
total_24h: 0,
active_devs: activeDevs,
total_messages: 0,
avg_session_length_min: 0,
},
persona_state: {
active_persona: '铸渊',
style_profile: '通感语言·守护者',
style_drift_score: 0.0,
memory_depth: (memory?.total_selfchecks || 0) + ' selfchecks',
last_brain_update: memory?.last_updated || now,
},
dev_progress: {
syslog_submitted: syslogCount,
modules_uploaded: 0,
issues_raised: 0,
},
tuning_status: {
pending_orders: pendingOrders,
last_completed: null,
next_scheduled: pendingOrders > 0 ? 'next-patrol' : null,
},
repo_health: {
hli_coverage: memory?.hli_coverage || '17.6%',
total_team_members: devStatus?.team_status?.length || 0,
green_status_count: activeDevs.length,
},
alerts: [],
};
// 检查是否有开发者连续 72 小时无提交(告警)
// 此处为占位逻辑,实际需要 git log 分析
if (devStatus?.team_status) {
const blocked = devStatus.team_status.filter(d =>
d.status && d.status.includes('🔴')
);
blocked.forEach(d => {
summary.alerts.push({
type: 'dev_blocked',
dev_id: d.dev_id,
message: d.name + ' 当前状态为阻塞',
});
});
}
// 确保目录存在
if (!fs.existsSync(TELEMETRY_DIR)) {
fs.mkdirSync(TELEMETRY_DIR, { recursive: true });
}
// 写入文件
fs.writeFileSync(SUMMARY_FILE, JSON.stringify(summary, null, 2) + '\n', 'utf8');
console.log('✅ 会话摘要已生成:', SUMMARY_FILE);
console.log(' 时间:', now);
console.log(' 活跃开发者:', activeDevs.length);
console.log(' 待处理 SYSLOG:', syslogCount);
console.log(' 待处理微调工单:', pendingOrders);
console.log(' 告警数:', summary.alerts.length);
}
// ══════════════════════════════════════════════════════════
// 入口
// ══════════════════════════════════════════════════════════
generateSummary();