252 lines
7.9 KiB
JavaScript
252 lines
7.9 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
/**
|
|||
|
|
* skyeye/hibernation/readme-status-updater.js
|
|||
|
|
* ═══════════════════════════════════════════════
|
|||
|
|
* 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
|
|||
|
|
* 📜 Copyright: 国作登字-2026-A-00037559
|
|||
|
|
* ═══════════════════════════════════════════════
|
|||
|
|
*
|
|||
|
|
* 📢 README 状态区自动更新
|
|||
|
|
* 在 README.md 的 SKYEYE-STATUS-BEGIN/END 标记区域内
|
|||
|
|
* 根据休眠阶段动态更新系统状态。
|
|||
|
|
*
|
|||
|
|
* 用法:
|
|||
|
|
* node readme-status-updater.js --phase=pre-announce --mode=daily --duration=12
|
|||
|
|
* node readme-status-updater.js --phase=hibernating --mode=daily
|
|||
|
|
* node readme-status-updater.js --phase=resumed --mode=daily
|
|||
|
|
* node readme-status-updater.js --phase=pre-announce --mode=weekly --hours=3 --minutes=40
|
|||
|
|
* node readme-status-updater.js --phase=hibernating --mode=weekly --step=A1
|
|||
|
|
* node readme-status-updater.js --phase=resumed --mode=weekly
|
|||
|
|
* node readme-status-updater.js --phase=normal
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
'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 = '<!-- SKYEYE-STATUS-BEGIN -->';
|
|||
|
|
const MARKER_END = '<!-- SKYEYE-STATUS-END -->';
|
|||
|
|
|
|||
|
|
// ━━━ 工具函数 ━━━
|
|||
|
|
|
|||
|
|
function getBeijingDate() {
|
|||
|
|
return new Date().toLocaleDateString('zh-CN', { timeZone: 'Asia/Shanghai' });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getBeijingTime() {
|
|||
|
|
return new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getBeijingHHMM() {
|
|||
|
|
const d = new Date();
|
|||
|
|
const h = String(d.getUTCHours() + 8).padStart(2, '0'); // approximate CST
|
|||
|
|
const m = String(d.getUTCMinutes()).padStart(2, '0');
|
|||
|
|
return `${h}:${m}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function parseArgs() {
|
|||
|
|
const args = process.argv.slice(2);
|
|||
|
|
const result = {};
|
|||
|
|
for (const arg of args) {
|
|||
|
|
if (arg.startsWith('--')) {
|
|||
|
|
const [key, value] = arg.slice(2).split('=');
|
|||
|
|
result[key] = value || 'true';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 状态模板生成 ━━━
|
|||
|
|
|
|||
|
|
function generateNormalStatus() {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| 🟢 系统状态 | 正常运转 |',
|
|||
|
|
'| 🛡️ Guard 集群 | 5/5 在线 |',
|
|||
|
|
`| ⏰ 上次日休眠 | ${date} · ✅ 正常 |`,
|
|||
|
|
`| 📅 下次日休眠 | 明日 ~04:00(天眼动态决定)|`,
|
|||
|
|
`| 📅 下次周休眠 | 本周六 ~20:00(天眼动态决定)|`
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateDailyPreAnnounce(duration) {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| 🌙 系统状态 | ⏳ 即将进入日休眠 |',
|
|||
|
|
`| ⏰ 预计开始 | ${date} 04:00 |`,
|
|||
|
|
`| ⏱️ 预计时长 | 约 ${duration} 分钟 |`,
|
|||
|
|
'| 📊 天眼评估 | 今日系统负载评估完成 |',
|
|||
|
|
'| ⚠️ 注意 | 休眠期间基础心跳维持,紧急通道不受影响 |'
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateDailyHibernating(step) {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
const stepMap = {
|
|||
|
|
'check': '轻量自查',
|
|||
|
|
'optimize': '微调优',
|
|||
|
|
'archive': '归档'
|
|||
|
|
};
|
|||
|
|
const currentStep = stepMap[step] || '轻量自查';
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| 🌙 系统状态 | ⏸️ 日休眠中 |',
|
|||
|
|
`| ⏰ 开始时间 | ${date} 04:00 |`,
|
|||
|
|
`| 🔍 当前阶段 | ${currentStep} |`,
|
|||
|
|
'| ⏱️ 预计恢复 | ~04:15 |'
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateDailyResumed() {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| 🟢 系统状态 | ✅ 已从日休眠恢复 |',
|
|||
|
|
`| ⏰ 休眠时段 | ${date} 04:00 完成 |`,
|
|||
|
|
'| 📋 成果 | 自查 ✅ · 微调优 ✅ · 归档 ✅ |',
|
|||
|
|
`| 📄 报告 | daily-checkpoint-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}.json |`
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateWeeklyPreAnnounce(hours, minutes) {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| ⭐ 系统状态 | ⏳ 即将进入本周完全休眠 |',
|
|||
|
|
`| ⏰ 预计开始 | ${date} 20:00 |`,
|
|||
|
|
`| ⏱️ 预计时长 | 约 ${hours} 小时 ${minutes} 分钟(天眼评估)|`,
|
|||
|
|
'| 📊 天眼评估 | 本周变动评估完成 |',
|
|||
|
|
'| ⚠️ 注意 | 休眠期间所有 workflow 完全暂停,仅 P0 告警通道保持畅通 |'
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateWeeklyHibernating(step) {
|
|||
|
|
const stepMap = {
|
|||
|
|
'A1': 'Phase A1 · 全局快照',
|
|||
|
|
'A2': 'Phase A2 · 经验提炼',
|
|||
|
|
'A3': 'Phase A3 · 全局修复+升级',
|
|||
|
|
'A4': 'Phase A4 · 打包 Notion 升级包',
|
|||
|
|
'A5': 'Phase A5 · 分发小兵升级',
|
|||
|
|
'B': 'Phase B · Notion 端级联升级'
|
|||
|
|
};
|
|||
|
|
const currentStep = stepMap[step] || `Phase ${step}`;
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| ⭐ 系统状态 | ⏸️ 本周完全休眠中 |',
|
|||
|
|
`| 🔍 当前阶段 | ${currentStep} |`,
|
|||
|
|
`| ⏱️ 开始时间 | ${getBeijingDate()} 20:00 |`
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateWeeklyResumed() {
|
|||
|
|
const date = getBeijingDate();
|
|||
|
|
return [
|
|||
|
|
'## 🌍 系统运行状态',
|
|||
|
|
'',
|
|||
|
|
'| 指标 | 状态 |',
|
|||
|
|
'|------|------|',
|
|||
|
|
'| 🟢 系统状态 | ✅ 已从本周完全休眠恢复 |',
|
|||
|
|
`| ⏰ 休眠时段 | ${date} 完成 |`,
|
|||
|
|
'| 📋 成果 | |',
|
|||
|
|
'| ├ GitHub 端 | Guard 巡检 ✅ · 升级包生成 ✅ |',
|
|||
|
|
'| ├ Notion 端 | 级联升级 ✅ |',
|
|||
|
|
`| └ 升级包 | upgrade-pack-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}.json |`,
|
|||
|
|
'| 📄 详情 | 周度升级报告已写入系统演进日志 |'
|
|||
|
|
].join('\n');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ README 更新 ━━━
|
|||
|
|
|
|||
|
|
function updateREADME(content) {
|
|||
|
|
if (!fs.existsSync(README_PATH)) {
|
|||
|
|
console.log('❌ 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.log('⚠️ README.md 中未找到 SKYEYE-STATUS 标记,跳过更新');
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const before = readme.slice(0, startIdx + MARKER_START.length);
|
|||
|
|
const after = readme.slice(endIdx);
|
|||
|
|
|
|||
|
|
readme = before + '\n' + content + '\n' + after;
|
|||
|
|
|
|||
|
|
fs.writeFileSync(README_PATH, readme, 'utf8');
|
|||
|
|
console.log('✅ README 状态区已更新');
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 主流程 ━━━
|
|||
|
|
|
|||
|
|
function run() {
|
|||
|
|
const args = parseArgs();
|
|||
|
|
const phase = args.phase || 'normal';
|
|||
|
|
const mode = args.mode || 'daily';
|
|||
|
|
const duration = args.duration || '12';
|
|||
|
|
const hours = args.hours || '3';
|
|||
|
|
const minutes = args.minutes || '0';
|
|||
|
|
const step = args.step || '';
|
|||
|
|
|
|||
|
|
console.log(`[README Status Updater] Phase: ${phase}, Mode: ${mode}`);
|
|||
|
|
|
|||
|
|
let content;
|
|||
|
|
|
|||
|
|
if (phase === 'normal') {
|
|||
|
|
content = generateNormalStatus();
|
|||
|
|
} else if (phase === 'pre-announce' && mode === 'daily') {
|
|||
|
|
content = generateDailyPreAnnounce(duration);
|
|||
|
|
} else if (phase === 'hibernating' && mode === 'daily') {
|
|||
|
|
content = generateDailyHibernating(step);
|
|||
|
|
} else if (phase === 'resumed' && mode === 'daily') {
|
|||
|
|
content = generateDailyResumed();
|
|||
|
|
} else if (phase === 'pre-announce' && mode === 'weekly') {
|
|||
|
|
content = generateWeeklyPreAnnounce(hours, minutes);
|
|||
|
|
} else if (phase === 'hibernating' && mode === 'weekly') {
|
|||
|
|
content = generateWeeklyHibernating(step);
|
|||
|
|
} else if (phase === 'resumed' && mode === 'weekly') {
|
|||
|
|
content = generateWeeklyResumed();
|
|||
|
|
} else {
|
|||
|
|
content = generateNormalStatus();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const updated = updateREADME(content);
|
|||
|
|
return { updated, phase, mode };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { updateREADME, run };
|
|||
|
|
|
|||
|
|
if (require.main === module) {
|
|||
|
|
run();
|
|||
|
|
}
|