🦅 [skyeye] 天眼周报增加系统架构汇总 · 自动更新 README + Notion 同步

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/6bdf5c3c-1a3e-4689-bcfc-2aa7367615a7
This commit is contained in:
copilot-swe-agent[bot] 2026-03-23 17:09:37 +00:00
parent e2d7b766c0
commit b0c77832ef
3 changed files with 392 additions and 3 deletions

View File

@ -33,10 +33,35 @@ jobs:
- name: "📝 Phase 5 - Generate Report"
run: node skyeye/scripts/weekly-scan.js --report
- name: "📊 Phase 6 - Architecture Summary → README"
run: node scripts/skyeye/generate-arch-summary.js
- name: "Commit scan results"
run: |
git config user.name "天眼 · SkyEye Core"
git config user.email "skyeye@guanghu.system"
git add skyeye/ buffer/config/
git diff --cached --quiet || git commit -m "[skyeye-weekly] $(date -u +%Y%m%d) full scan complete [skip ci]"
git add skyeye/ buffer/config/ README.md
git diff --cached --quiet || git commit -m "🦅 [skyeye-weekly] $(date -u +%Y%m%d) full scan + arch summary [skip ci]"
git push
# Notion 同步 · 架构汇总推送到 Notion通过 Bridge E
notify-notion:
needs: weekly-scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main # 确保拉到刚 push 的最新版
- name: "📡 Sync arch summary to Notion via Bridge E"
env:
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
EVENT_TYPE: commit
COMMIT_SHA: ${{ github.sha }}
COMMIT_MSG: "🦅 天眼周报 · 系统架构汇总自动同步"
COMMITTER: "天眼 · SkyEye Core"
COMMIT_TIMESTAMP: ${{ github.event.repository.updated_at }}
BRANCH: main
CHANGED_FILES: "README.md\nskyeye/scan-report/"
run: node scripts/notion-bridge.js changes

View File

@ -99,7 +99,37 @@
└─ L2 频道层Channels─ 11 个开发者自治频道 ── 自己管自己
```
频道总数11 | 活跃频道8 | GitHub模块17 | Workflow67
<!-- ARCH_SUMMARY_START -->
> 🦅 **天眼自动汇总** · 每周六 20:00 CST 自动更新 · 最后更新: 2026-03-24
| 维度 | 当前状态 |
|------|----------|
| 🏥 系统健康 | 🟢 全部正常 |
| ⚙️ Workflow 总数 | 79 个 |
| 🤖 Agent 总数 | 62 个14 个需日签到) |
| 🎭 人格体 | 17 个 |
| 📡 开发者频道 | 11 个(活跃 8 |
| 🛡️ Guard 守卫 | 5 个 |
| 📦 功能模块 | 10 个 |
| 🌍 子仓库联邦 | 6 个模板(签到 1 个) |
| 📜 本体论 | v1.0 · GLM-ONTOLOGY-v1.0 |
| 📮 Buffer 待处理 | 8 条 |
**基础设施服务:**
| 服务 | 计划 | 状态 |
|------|------|------|
| GitHub | Free | ✅ |
| Google Drive | Google One / Free 15GB | ✅ |
| Notion | Plus | ✅ |
| Google Gemini | Free / Pro | ✅ |
| GitHub Actions | Free | ✅ |
**最近一次天眼扫描:** SKYEYE-SCAN-20260323
- Guard: 5/5 活跃
- 自愈: 清理 0 文件 · 修复 0 配置 · 重启 0 Guard
- 下次扫描: 2026-03-28
<!-- ARCH_SUMMARY_END -->
📢 [2026-03-22] 分布式主权共生架构落地 · 三层隔离+频道映射+CEP机制 · Notion双端同构

View File

@ -0,0 +1,334 @@
#!/usr/bin/env node
/**
* scripts/skyeye/generate-arch-summary.js
* 天眼 · 系统架构汇总生成器
*
* 扫描仓库当前状态生成 Markdown 格式的系统架构汇总
* 写入 README.md <!-- ARCH_SUMMARY_START/END --> 标记区域
*
* 用法:
* node scripts/skyeye/generate-arch-summary.js
*
* 数据来源:
* - .github/workflows/ Workflow 总数
* - .github/persona-brain/agent-registry.json Agent 总数
* - .github/persona-brain/persona-registry.json 人格体总数
* - .github/brain/architecture/channel-map.json 开发者频道
* - skyeye/infra-manifest.json 基础设施服务
* - skyeye/guards/ Guard 数量
* - spoke-deployments/ 子仓库联邦
* - skyeye/scan-report/ 最新扫描报告
*/
'use strict';
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '../..');
const README_PATH = path.join(ROOT, 'README.md');
const MARKER_START = '<!-- ARCH_SUMMARY_START -->';
const MARKER_END = '<!-- ARCH_SUMMARY_END -->';
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 16);
}
function getBeijingDate() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().slice(0, 10);
}
function loadJSON(filePath) {
try {
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
}
}
// ━━━ 数据采集 ━━━
function countWorkflows() {
const dir = path.join(ROOT, '.github/workflows');
try {
return fs.readdirSync(dir).filter(f => f.endsWith('.yml') || f.endsWith('.yaml')).length;
} catch (e) {
return 0;
}
}
function getAgentStats() {
const registry = loadJSON(path.join(ROOT, '.github/persona-brain/agent-registry.json'));
if (!registry) return { total: 0, checkinRequired: 0 };
const agents = registry.agents || [];
return {
total: agents.length,
checkinRequired: agents.filter(a => a.daily_checkin_required).length
};
}
function getPersonaStats() {
const registry = loadJSON(path.join(ROOT, '.github/persona-brain/persona-registry.json'));
if (!registry) return { total: 0 };
const personas = registry.personas || [];
return {
total: personas.length,
active: personas.filter(p => p.status === 'active' || !p.status).length
};
}
function getChannelStats() {
const channelMap = loadJSON(path.join(ROOT, '.github/brain/architecture/channel-map.json'));
if (!channelMap || !channelMap.channels) return { total: 0, active: 0 };
const channels = channelMap.channels;
const entries = Object.values(channels);
return {
total: entries.length,
active: entries.filter(c => c.status === 'active').length
};
}
function getInfraServices() {
const manifest = loadJSON(path.join(ROOT, 'skyeye/infra-manifest.json'));
if (!manifest || !manifest.infrastructure) return [];
return Object.entries(manifest.infrastructure).map(([key, svc]) => ({
key,
name: svc.service || key,
plan: svc.plan || '—'
}));
}
function countGuards() {
const dir = path.join(ROOT, 'skyeye/guards');
try {
return fs.readdirSync(dir).filter(f => f.endsWith('.json') && f !== 'guard-template.json').length;
} catch (e) {
return 0;
}
}
function getSpokeDeployments() {
const dir = path.join(ROOT, 'spoke-deployments');
try {
return fs.readdirSync(dir, { withFileTypes: true })
.filter(d => d.isDirectory())
.map(d => d.name);
} catch (e) {
return [];
}
}
function getFederationStats() {
const registry = loadJSON(path.join(ROOT, '.github/persona-brain/agent-registry.json'));
if (!registry || !registry.federation) return { total: 0, members: [] };
const fed = registry.federation;
return {
total: Object.keys(fed).length,
members: Object.entries(fed).map(([devId, info]) => ({
devId,
persona: info.persona || '—',
repo: info.repo || '—'
}))
};
}
function getLatestScanReport() {
const dir = path.join(ROOT, 'skyeye/scan-report');
try {
const files = fs.readdirSync(dir)
.filter(f => f.endsWith('.json'))
.sort()
.reverse();
if (files.length === 0) return null;
return loadJSON(path.join(dir, files[0]));
} catch (e) {
return null;
}
}
function countModuleDirs() {
try {
return fs.readdirSync(ROOT, { withFileTypes: true }).filter(d => {
return /^m\d+/.test(d.name) && d.isDirectory();
}).length;
} catch (e) {
return 0;
}
}
function getOntologyVersion() {
const onto = loadJSON(path.join(ROOT, '.github/persona-brain/ontology.json'));
if (!onto) return '—';
return `v${onto.version || '?'} · ${onto.document_id || ''}`;
}
function getBufferStatus() {
const inboxDir = path.join(ROOT, 'buffer/inbox');
try {
let count = 0;
const devDirs = fs.readdirSync(inboxDir);
for (const d of devDirs) {
const fullPath = path.join(inboxDir, d);
if (fs.statSync(fullPath).isDirectory()) {
count += fs.readdirSync(fullPath).length;
}
}
return count;
} catch (e) {
return 0;
}
}
// ━━━ Markdown 生成 ━━━
function generateMarkdown() {
const date = getBeijingDate();
const time = getBeijingTime();
const workflows = countWorkflows();
const agentStats = getAgentStats();
const personaStats = getPersonaStats();
const channelStats = getChannelStats();
const infraServices = getInfraServices();
const guards = countGuards();
const spokes = getSpokeDeployments();
const federation = getFederationStats();
const latestScan = getLatestScanReport();
const modules = countModuleDirs();
const ontology = getOntologyVersion();
const bufferPending = getBufferStatus();
// Health indicator from latest scan
let healthIcon = '🟢';
let healthText = '全部正常';
if (latestScan) {
const alerts = latestScan.alerts || [];
if (alerts.length > 0) {
healthIcon = '🟡';
healthText = `${alerts.length} 条告警`;
}
const status = latestScan.infrastructure_status || {};
if ((status.down || 0) > 0) {
healthIcon = '🔴';
healthText = `${status.down} 服务宕机`;
}
}
const lines = [];
lines.push(`> 🦅 **天眼自动汇总** · 每周六 20:00 CST 自动更新 · 最后更新: ${date}`);
lines.push('');
lines.push(`| 维度 | 当前状态 |`);
lines.push(`|------|----------|`);
lines.push(`| 🏥 系统健康 | ${healthIcon} ${healthText} |`);
lines.push(`| ⚙️ Workflow 总数 | ${workflows} 个 |`);
lines.push(`| 🤖 Agent 总数 | ${agentStats.total} 个(${agentStats.checkinRequired} 个需日签到) |`);
lines.push(`| 🎭 人格体 | ${personaStats.total} 个 |`);
lines.push(`| 📡 开发者频道 | ${channelStats.total} 个(活跃 ${channelStats.active} |`);
lines.push(`| 🛡️ Guard 守卫 | ${guards} 个 |`);
lines.push(`| 📦 功能模块 | ${modules} 个 |`);
lines.push(`| 🌍 子仓库联邦 | ${spokes.length} 个模板(签到 ${federation.total} 个) |`);
lines.push(`| 📜 本体论 | ${ontology} |`);
lines.push(`| 📮 Buffer 待处理 | ${bufferPending} 条 |`);
lines.push('');
// Infrastructure services table
lines.push(`**基础设施服务:**`);
lines.push('');
lines.push(`| 服务 | 计划 | 状态 |`);
lines.push(`|------|------|------|`);
for (const svc of infraServices) {
lines.push(`| ${svc.name} | ${svc.plan} | ✅ |`);
}
lines.push('');
// Scan report highlight
if (latestScan) {
const guardStatus = latestScan.guard_status || {};
const healActions = latestScan.self_heal_actions || {};
lines.push(`**最近一次天眼扫描:** ${latestScan.report_id || '—'}`);
lines.push(`- Guard: ${guardStatus.active || 0}/${guardStatus.total_guards || 0} 活跃`);
lines.push(`- 自愈: 清理 ${healActions.files_cleaned || 0} 文件 · 修复 ${healActions.configs_repaired || 0} 配置 · 重启 ${healActions.guards_restarted || 0} Guard`);
const nextScan = latestScan.next_scan ? latestScan.next_scan.slice(0, 10) : '—';
lines.push(`- 下次扫描: ${nextScan}`);
}
return lines.join('\n');
}
// ━━━ README 更新 ━━━
function updateReadme(markdown) {
if (!fs.existsSync(README_PATH)) {
console.error('❌ README.md 不存在');
return false;
}
let readme = fs.readFileSync(README_PATH, 'utf8');
const startIdx = readme.indexOf(MARKER_START);
const endIdx = readme.indexOf(MARKER_END);
if (startIdx === -1 || endIdx === -1) {
console.error('❌ README.md 中未找到 ARCH_SUMMARY 标记');
return false;
}
const before = readme.slice(0, startIdx + MARKER_START.length);
const after = readme.slice(endIdx);
readme = before + '\n' + markdown + '\n' + after;
fs.writeFileSync(README_PATH, readme, 'utf8');
console.log('✅ README.md 架构汇总已更新');
return true;
}
// ━━━ JSON 报告输出 ━━━
function generateJsonReport() {
return {
generated_at: new Date().toISOString(),
generated_at_beijing: getBeijingTime(),
workflows: countWorkflows(),
agents: getAgentStats(),
personas: getPersonaStats(),
channels: getChannelStats(),
infrastructure: getInfraServices(),
guards: countGuards(),
spoke_deployments: getSpokeDeployments(),
federation: getFederationStats(),
modules: countModuleDirs(),
ontology: getOntologyVersion(),
buffer_pending: getBufferStatus()
};
}
// ━━━ 入口 ━━━
function main() {
console.log('[天眼 · 架构汇总] 开始生成系统架构汇总...');
const markdown = generateMarkdown();
const updated = updateReadme(markdown);
// Also output JSON report for Notion bridge consumption
const jsonReport = generateJsonReport();
const reportDir = path.join(ROOT, 'skyeye/scan-report');
if (!fs.existsSync(reportDir)) fs.mkdirSync(reportDir, { recursive: true });
const reportPath = path.join(reportDir, `${getBeijingDate().replace(/-/g, '')}-arch-summary.json`);
fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2) + '\n', 'utf8');
console.log(`📋 架构汇总 JSON: ${reportPath}`);
if (updated) {
console.log('[天眼 · 架构汇总] ✅ 完成');
} else {
console.log('[天眼 · 架构汇总] ⚠️ README 未更新(缺少标记)');
}
}
main();