Merge pull request #97 from qinfendebingshuo/copilot/update-upload-notification-logic

feat: 公告栏改为追加式更新,每日自动清空
This commit is contained in:
冰朔 2026-03-14 16:25:22 +08:00 committed by GitHub
commit 4aa5d429e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 103 additions and 21 deletions

View File

@ -0,0 +1 @@
{"date":"","records":[]}

View File

@ -22,6 +22,24 @@ jobs:
with:
node-version: '20'
# ── Step 0: 清空公告栏缓存(每日重置) ──
- name: 清空公告栏缓存
run: |
CACHE_FILE=".github/brain/bulletin-board-today.json"
TODAY=$(TZ="Asia/Shanghai" date +%Y-%m-%d)
if [ -f "$CACHE_FILE" ]; then
CACHE_DATE=$(jq -r '.date // ""' "$CACHE_FILE" 2>/dev/null || echo "")
if [ "$CACHE_DATE" != "$TODAY" ]; then
echo "{\"date\":\"$TODAY\",\"records\":[]}" > "$CACHE_FILE"
echo "✅ 公告栏缓存已清空(旧日期: $CACHE_DATE"
else
echo "📌 公告栏缓存日期匹配今天 ($TODAY),无需清空"
fi
else
echo "{\"date\":\"$TODAY\",\"records\":[]}" > "$CACHE_FILE"
echo "✅ 创建新的公告栏缓存文件"
fi
# ── Step 1: 检查 brain/ 目录完整性 ──
- name: 检查 brain/ 目录完整性
id: brain_check
@ -96,7 +114,7 @@ jobs:
run: |
git config user.name "铸渊 Maintenance Agent"
git config user.email "actions@guanghulab.com"
git add brain/system-health.json
git add brain/system-health.json .github/brain/bulletin-board-today.json
if git diff --cached --quiet; then
echo "📌 无变更需要提交"
else

View File

@ -77,7 +77,7 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add README.md
git add README.md .github/brain/bulletin-board-today.json
if git diff --cached --quiet; then
echo "📢 公告区无变化,跳过提交"
else

View File

@ -30,6 +30,7 @@ const MEMORY_PATH = path.join(__dirname, '..', '.github', 'brain', 'memory.json'
const PERSONA_MEMORY_PATH = path.join(__dirname, '..', '.github', 'persona-brain', 'memory.json');
const DEV_STATUS_PATH = path.join(__dirname, '..', '.github', 'persona-brain', 'dev-status.json');
const COLLABORATORS_PATH = path.join(__dirname, '..', '.github', 'brain', 'collaborators.json');
const BULLETIN_CACHE_PATH = path.join(__dirname, '..', '.github', 'brain', 'bulletin-board-today.json');
const MAX_BINGSHUO_ENTRIES = 15;
const MAX_COLLAB_ENTRIES = 20;
@ -101,6 +102,21 @@ function formatTime(ts) {
return `${get('month')}-${get('day')} ${get('hour')}:${get('minute')}`;
}
function formatTimeShort(ts) {
if (!ts) return '—';
const d = new Date(ts);
if (isNaN(d.getTime())) return '—';
const fmt = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
hour: '2-digit',
minute: '2-digit',
hour12: false,
});
const parts = fmt.formatToParts(d);
const get = (type) => (parts.find(p => p.type === type) || {}).value || '';
return `${get('hour')}:${get('minute')}`;
}
function todayDateStr() {
const fmt = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
@ -149,6 +165,54 @@ function loadMemoryEvents() {
return events;
}
/* ── 公告栏缓存(当日追加式) ─────────────────────────── */
function loadBulletinCache() {
const today = todayDateStr();
try {
if (fs.existsSync(BULLETIN_CACHE_PATH)) {
const cache = JSON.parse(fs.readFileSync(BULLETIN_CACHE_PATH, 'utf8'));
if (cache.date === today) {
return cache;
}
}
} catch (err) {
console.log(`⚠️ 公告栏缓存读取失败: ${err.message}`);
}
return { date: today, records: [] };
}
function saveBulletinCache(cache) {
try {
fs.writeFileSync(BULLETIN_CACHE_PATH, JSON.stringify(cache, null, 2), 'utf8');
} catch (err) {
console.log(`⚠️ 公告栏缓存写入失败: ${err.message}`);
}
}
function appendToCache(cache, newEntries) {
const existingKeys = new Set(cache.records.map(r => r.key));
let added = 0;
for (const e of newEntries) {
const key = `${e.actor}|${e.module || '—'}|${e.ts || ''}`;
if (!existingKeys.has(key)) {
existingKeys.add(key);
cache.records.push({
key,
ts: e.ts,
actor: e.actor,
module: e.module || '—',
result: e.result,
icon: e.icon,
sortKey: e.sortKey,
});
added++;
}
}
cache.records.sort((a, b) => a.sortKey - b.sortKey);
return added;
}
/* ── 分类事件为冰朔/合作者 ─────────────────────────── */
function classifyEvents(events) {
@ -474,26 +538,19 @@ function buildBingshuoAlert(issues) {
return alert;
}
/* ── 生成合作者公告表格 ─────────────────────────── */
/* ── 生成合作者公告表格(追加式,从缓存构建) ─────────────────────────── */
function buildCollabBulletin(entries) {
const sorted = [...entries].sort((a, b) => b.sortKey - a.sortKey);
const seen = new Set();
const unique = [];
for (const e of sorted) {
const key = `${e.actor}|${e.module}|${formatTime(e.ts)}`;
if (!seen.has(key)) { seen.add(key); unique.push(e); }
}
const display = unique.slice(0, MAX_COLLAB_ENTRIES);
function buildCollabBulletin(cacheRecords) {
const today = todayDateStr();
const display = cacheRecords.slice(0, MAX_COLLAB_ENTRIES);
if (display.length === 0) {
return '| 时间 | 合作者 | 模块 | 状态 |\n|------|--------|------|------|\n| 🕐 暂无记录 | — | — | 等待模块推送 |';
return `👥 合作者公告栏(${today}\n\n| 时间 | 合作者 | 模块 | 状态 |\n|------|--------|------|------|\n| 🕐 暂无记录 | — | — | 等待模块推送 |`;
}
const rows = display.map(e =>
`| ${formatTime(e.ts)} | ${e.actor} | \`${e.module || '—'}/\` | ${e.icon} ${e.result === 'success' || e.result === 'passed' ? '上传成功' : e.result === 'failed' || e.result === 'failure' ? '❌ 上传失败' : '已更新'} |`
`| ${formatTimeShort(e.ts)} | ${e.actor} | \`${e.module || '—'}/\` | ${e.icon} ${e.result === 'success' || e.result === 'passed' ? '上传成功' : e.result === 'failed' || e.result === 'failure' ? '❌ 上传失败' : '已更新'} |`
);
return `| 时间 | 合作者 | 模块 | 状态 |\n|------|--------|------|------|\n${rows.join('\n')}`;
return `👥 合作者公告栏(${today}\n\n| 时间 | 合作者 | 模块 | 状态 |\n|------|--------|------|------|\n${rows.join('\n')}`;
}
/* ── 生成合作者提醒 ─────────────────────────── */
@ -687,18 +744,24 @@ async function main() {
console.log(`\n📊 冰朔合计: ${allBingshuo.length}`);
console.log(`📊 合作者合计: ${allCollab.length}\n`);
// 5. 检测需要干预的问题
// 5. 合作者公告栏:追加式缓存
const cache = loadBulletinCache();
const addedCount = appendToCache(cache, allCollab);
saveBulletinCache(cache);
console.log(`📋 公告栏缓存: ${cache.records.length} 条记录(本次新增 ${addedCount} 条)`);
// 6. 检测需要干预的问题
const { bingshuoIssues, collabIssuesByDev } = detectIssues(allBingshuo, allCollab);
console.log(`🔴 冰朔待处理: ${bingshuoIssues.length}`);
console.log(`🔴 合作者待处理: ${Object.keys(collabIssuesByDev).length}\n`);
// 6. 生成各区域内容
// 7. 生成各区域内容
const bingshuoBulletin = buildBingshuoBulletin(allBingshuo);
const bingshuoAlert = buildBingshuoAlert(bingshuoIssues);
const collabBulletin = buildCollabBulletin(allCollab);
const collabBulletin = buildCollabBulletin(cache.records);
const collabAlert = buildCollabAlert(collabIssuesByDev);
// 7. 更新 README.md
// 8. 更新 README.md
if (!fs.existsSync(README_PATH)) {
console.error('❌ README.md 不存在');
process.exit(1);
@ -718,7 +781,7 @@ async function main() {
console.log('✅ README.md 公告区已更新');
}
// 8. 发送邮件(如有需要)
// 9. 发送邮件(如有需要)
if (bingshuoIssues.length > 0 || Object.keys(collabIssuesByDev).length > 0) {
await sendAlertEmails(bingshuoIssues, collabIssuesByDev);
}