179 lines
5.7 KiB
JavaScript
179 lines
5.7 KiB
JavaScript
|
|
/**
|
|||
|
|
* scripts/agent-checkin.js
|
|||
|
|
* 人格体每日签到脚本
|
|||
|
|
*
|
|||
|
|
* 逻辑:
|
|||
|
|
* 1. 读取 agent-registry.json 获取所有注册小兵列表
|
|||
|
|
* 2. 对每个小兵,查询 GitHub Actions API 获取该 workflow 今日最新一次 run 的结果
|
|||
|
|
* 3. 结果为 success 且时间在今天 10:00 之前 → 标记为 ✅ 已签到
|
|||
|
|
* 4. 结果为 failure 或无今日 run → 标记为 ❌ 未签到
|
|||
|
|
* 5. 更新 checkin-board.json 的所有记录
|
|||
|
|
* 6. 生成 summary(总数/已签到/缺席/缺席名单)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
'use strict';
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const https = require('https');
|
|||
|
|
|
|||
|
|
const ROOT = path.resolve(__dirname, '..');
|
|||
|
|
const BRAIN_DIR = path.join(ROOT, '.github/persona-brain');
|
|||
|
|
const REGISTRY_PATH = path.join(BRAIN_DIR, 'agent-registry.json');
|
|||
|
|
const BOARD_PATH = path.join(BRAIN_DIR, 'checkin-board.json');
|
|||
|
|
|
|||
|
|
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
|
|||
|
|
const REPO = process.env.GITHUB_REPOSITORY || 'qinfendebingshuo/guanghulab';
|
|||
|
|
|
|||
|
|
const today = new Date().toISOString().split('T')[0];
|
|||
|
|
const todayStart = new Date(today + 'T00:00:00Z');
|
|||
|
|
|
|||
|
|
console.log(`📋 人格体每日签到开始 · ${today}`);
|
|||
|
|
|
|||
|
|
// ── GitHub API helper ─────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
function githubApi(urlPath) {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
const options = {
|
|||
|
|
hostname: 'api.github.com',
|
|||
|
|
path: urlPath,
|
|||
|
|
method: 'GET',
|
|||
|
|
headers: {
|
|||
|
|
'User-Agent': 'zhuyuan-agent-checkin',
|
|||
|
|
'Accept': 'application/vnd.github.v3+json',
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
if (GITHUB_TOKEN) {
|
|||
|
|
options.headers['Authorization'] = `Bearer ${GITHUB_TOKEN}`;
|
|||
|
|
}
|
|||
|
|
const req = https.request(options, (res) => {
|
|||
|
|
let data = '';
|
|||
|
|
res.on('data', (chunk) => { data += chunk; });
|
|||
|
|
res.on('end', () => {
|
|||
|
|
try {
|
|||
|
|
resolve(JSON.parse(data));
|
|||
|
|
} catch {
|
|||
|
|
resolve(null);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
req.on('error', (err) => {
|
|||
|
|
console.error(` ⚠️ API 请求失败: ${err.message}`);
|
|||
|
|
resolve(null);
|
|||
|
|
});
|
|||
|
|
req.end();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── 获取 workflow 今日最新 run ────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
async function getLatestRun(workflowFile) {
|
|||
|
|
const urlPath = `/repos/${REPO}/actions/workflows/${encodeURIComponent(workflowFile)}/runs?per_page=1&created=${encodeURIComponent('>=' + today)}`;
|
|||
|
|
const data = await githubApi(urlPath);
|
|||
|
|
if (!data || !data.workflow_runs || data.workflow_runs.length === 0) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
const run = data.workflow_runs[0];
|
|||
|
|
return {
|
|||
|
|
status: run.status,
|
|||
|
|
conclusion: run.conclusion,
|
|||
|
|
created_at: run.created_at,
|
|||
|
|
updated_at: run.updated_at,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ── 主签到流程 ────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
async function main() {
|
|||
|
|
// 1. 读取注册表
|
|||
|
|
if (!fs.existsSync(REGISTRY_PATH)) {
|
|||
|
|
console.error('❌ agent-registry.json 不存在');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
const registry = JSON.parse(fs.readFileSync(REGISTRY_PATH, 'utf8'));
|
|||
|
|
|
|||
|
|
// 2. 构建签到记录(仅检查 daily_checkin_required === true 的 Agent)
|
|||
|
|
const records = [];
|
|||
|
|
let checkedIn = 0;
|
|||
|
|
const missingAgents = [];
|
|||
|
|
let skipped = 0;
|
|||
|
|
|
|||
|
|
for (const agent of registry.agents) {
|
|||
|
|
// 跳过无需每日签到的 Agent(事件触发型、已暂停等)
|
|||
|
|
if (agent.daily_checkin_required === false) {
|
|||
|
|
skipped++;
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log(` 🔍 检查 ${agent.id} (${agent.workflow})...`);
|
|||
|
|
const run = await getLatestRun(agent.workflow);
|
|||
|
|
|
|||
|
|
const record = {
|
|||
|
|
agent_id: agent.id,
|
|||
|
|
agent_name: agent.name,
|
|||
|
|
status: 'pending',
|
|||
|
|
checkin_time: null,
|
|||
|
|
last_run: null,
|
|||
|
|
last_run_result: null,
|
|||
|
|
note: '',
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (run && run.conclusion === 'success') {
|
|||
|
|
record.status = '✅ 已签到';
|
|||
|
|
record.checkin_time = run.updated_at;
|
|||
|
|
record.last_run = run.updated_at;
|
|||
|
|
record.last_run_result = 'success';
|
|||
|
|
checkedIn++;
|
|||
|
|
console.log(` ✅ 已签到 (${run.updated_at})`);
|
|||
|
|
} else if (run) {
|
|||
|
|
record.status = '❌ 未签到';
|
|||
|
|
record.last_run = run.updated_at;
|
|||
|
|
record.last_run_result = run.conclusion || run.status;
|
|||
|
|
record.note = `最近运行结果: ${run.conclusion || run.status}`;
|
|||
|
|
missingAgents.push(agent.id);
|
|||
|
|
console.log(` ❌ 未签到 (结果: ${run.conclusion || run.status})`);
|
|||
|
|
} else {
|
|||
|
|
record.status = '❌ 未签到';
|
|||
|
|
record.note = '今日无运行记录';
|
|||
|
|
missingAgents.push(agent.id);
|
|||
|
|
console.log(` ❌ 未签到 (今日无运行记录)`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
records.push(record);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log(`\n📋 跳过 ${skipped} 个无需签到的 Agent`);
|
|||
|
|
|
|||
|
|
// 3. 构建签到板
|
|||
|
|
const board = {
|
|||
|
|
board_version: 'v1.0',
|
|||
|
|
checkin_deadline: '10:00+08:00',
|
|||
|
|
inspection_time: '12:00+08:00',
|
|||
|
|
date: today,
|
|||
|
|
records: records,
|
|||
|
|
summary: {
|
|||
|
|
total: records.length,
|
|||
|
|
checked_in: checkedIn,
|
|||
|
|
missing: records.length - checkedIn,
|
|||
|
|
missing_agents: missingAgents,
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 4. 写入签到板
|
|||
|
|
fs.writeFileSync(BOARD_PATH, JSON.stringify(board, null, 2));
|
|||
|
|
|
|||
|
|
console.log(`\n📊 签到汇总:`);
|
|||
|
|
console.log(` 总数: ${board.summary.total}`);
|
|||
|
|
console.log(` 已签到: ${board.summary.checked_in}`);
|
|||
|
|
console.log(` 缺席: ${board.summary.missing}`);
|
|||
|
|
if (missingAgents.length > 0) {
|
|||
|
|
console.log(` 缺席名单: ${missingAgents.join(', ')}`);
|
|||
|
|
}
|
|||
|
|
console.log(`\n✅ 签到记录已写入 checkin-board.json`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
main().catch((err) => {
|
|||
|
|
console.error('❌ 签到脚本异常:', err.message);
|
|||
|
|
process.exit(1);
|
|||
|
|
});
|