refactor: 提取共享 dev-suffix-map 模块 + 修复代码审查反馈

- 创建 scripts/utils/dev-suffix-map.js (共享后缀→DEV-ID映射)
- 更新 verify-modules.js + push-broadcast-to-github.js 使用共享映射
- 移动 require 到文件顶部 (invoke-persona.js, create-standardized-ticket.js)
- 心跳监控参数可配置化 (HEARTBEAT_TIMEOUT_MINUTES, MAX_RETRY_COUNT)

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-13 06:37:11 +00:00
parent e0dbe71bdc
commit c9d6495e5f
6 changed files with 50 additions and 26 deletions

View File

@ -18,6 +18,7 @@
'use strict';
const https = require('https');
const fs = require('fs');
const NOTION_TOKEN = process.env.NOTION_TOKEN || '';
const NOTION_TICKET_DB_ID = process.env.NOTION_TICKET_DB_ID || '';
@ -184,7 +185,6 @@ async function createStandardizedTicket() {
// 输出工单 ID 到 GITHUB_OUTPUT
var outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
var fs = require('fs');
fs.appendFileSync(outputFile, 'ticket_page_id=' + result.id + '\n');
fs.appendFileSync(outputFile, 'ticket_url=' + (result.url || '') + '\n');
}

View File

@ -24,6 +24,7 @@ const https = require('https');
const http = require('http');
const fs = require('fs');
const path = require('path');
const childProcess = require('child_process');
// ══════════════════════════════════════════════════════════
// 配置
@ -166,7 +167,6 @@ async function invokePersona(workOrder) {
process.env.AUTHOR = workOrder.developer;
// 执行 wake-persona.jsfork 子进程)
var childProcess = require('child_process');
var wakeScript = path.join(__dirname, 'wake-persona.js');
return new Promise(function (resolve, reject) {

View File

@ -30,8 +30,8 @@ var SMTP_USER = process.env.SMTP_USER || '';
var SMTP_PASS = process.env.SMTP_PASS || '';
var NOTION_VERSION = '2022-06-28';
var HEARTBEAT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
var MAX_RETRIES = 3;
var HEARTBEAT_TIMEOUT_MS = (parseInt(process.env.HEARTBEAT_TIMEOUT_MINUTES, 10) || 5) * 60 * 1000;
var MAX_RETRIES = parseInt(process.env.MAX_RETRY_COUNT, 10) || 3;
var REPO_OWNER = 'qinfendebingshuo';
var REPO_NAME = 'guanghulab';

View File

@ -18,6 +18,7 @@
var https = require('https');
var fs = require('fs');
var devSuffixMap = require('./utils/dev-suffix-map');
var GITHUB_TOKEN = process.env.GITHUB_TOKEN || '';
var BROADCAST_ID = process.env.BROADCAST_ID || '';
@ -94,16 +95,7 @@ async function pushBroadcast() {
// 确定开发者 ID从广播编号提取或使用环境变量
var devId = DEVELOPER_ID;
if (!devId) {
// 从 BROADCAST_ID 提取后缀 → 映射到 DEV-XXX
var suffixMatch = BROADCAST_ID.match(/BC-[A-Z0-9]+-\d+-([A-Z]+)/i);
var suffix = suffixMatch ? suffixMatch[1].toUpperCase() : '';
var suffixMap = {
'YY': 'DEV-001', 'FM': 'DEV-002', 'YF': 'DEV-003',
'ZZ': 'DEV-004', 'XCM': 'DEV-005', 'HE': 'DEV-009',
'JZ': 'DEV-010', 'CCNN': 'DEV-011', 'AW': 'DEV-012',
'XX': 'DEV-013', 'SY': 'DEV-014',
};
devId = suffixMap[suffix] || 'UNKNOWN';
devId = devSuffixMap.getDevIdFromBroadcast(BROADCAST_ID) || 'UNKNOWN';
}
// 构建路径和提交信息

View File

@ -0,0 +1,38 @@
// scripts/utils/dev-suffix-map.js
// 开发者广播编号后缀 → DEV-ID 映射表
//
// 广播编号格式: BC-{模块}-{序号}-{后缀}
// 后缀是开发者名字拼音首字母缩写
'use strict';
// 后缀→开发者编号映射
var SUFFIX_MAP = {
'YY': 'DEV-001', // 页页
'FM': 'DEV-002', // 肥猫
'YF': 'DEV-003', // 燕樊
'ZZ': 'DEV-004', // 之之
'XCM': 'DEV-005', // 小草莓
'HE': 'DEV-009', // 花尔
'JZ': 'DEV-010', // 桔子
'CCNN': 'DEV-011', // 匆匆那年
'AW': 'DEV-012', // Awen
'XX': 'DEV-013', // 小兴
'SY': 'DEV-014', // 时雨
};
/**
* 从广播编号中提取开发者编号
* @param {string} broadcastId - 广播编号 BC-M22-009-AW
* @returns {string} 开发者编号 DEV-012未找到返回空字符串
*/
function getDevIdFromBroadcast(broadcastId) {
var suffixMatch = (broadcastId || '').match(/BC-[A-Z0-9]+-\d+-([A-Z]+)/i);
var suffix = suffixMatch ? suffixMatch[1].toUpperCase() : '';
return SUFFIX_MAP[suffix] || '';
}
module.exports = {
SUFFIX_MAP: SUFFIX_MAP,
getDevIdFromBroadcast: getDevIdFromBroadcast,
};

View File

@ -17,6 +17,7 @@
const fs = require('fs');
const path = require('path');
const devSuffixMap = require('./utils/dev-suffix-map');
const SYSLOG_CONTENT = process.env.SYSLOG_CONTENT || '';
const BROADCAST_ID = process.env.BROADCAST_ID || '';
@ -67,25 +68,18 @@ function extractDevId(content, broadcastId) {
var devMatch = content.match(/\b(DEV-\d{3})\b/i);
if (devMatch) return devMatch[1].toUpperCase();
// 从广播编号提取开发者后缀(如 BC-M22-009-AW → AW
// 从广播编号提取开发者编号(使用共享映射表)
var mappedDevId = devSuffixMap.getDevIdFromBroadcast(broadcastId);
if (mappedDevId) return mappedDevId;
// 兜底:从 dev-status.json 匹配
var suffixMatch = broadcastId.match(/BC-[A-Z0-9]+-\d+-([A-Z]+)/i);
var devSuffix = suffixMatch ? suffixMatch[1].toUpperCase() : '';
// 从 dev-status.json 通过后缀匹配开发者
if (devSuffix) {
try {
var devStatus = JSON.parse(fs.readFileSync(DEV_STATUS_PATH, 'utf8'));
var team = devStatus.team || [];
// 后缀缩写映射表(从 dev-status.json 中名字的拼音首字母)
var suffixMap = {
'YY': 'DEV-001', 'FM': 'DEV-002', 'YF': 'DEV-003',
'ZZ': 'DEV-004', 'XCM': 'DEV-005', 'HE': 'DEV-009',
'JZ': 'DEV-010', 'CCNN': 'DEV-011', 'AW': 'DEV-012',
'XX': 'DEV-013', 'SY': 'DEV-014',
};
if (suffixMap[devSuffix]) return suffixMap[devSuffix];
// 兜底:尝试从 team 中匹配 waiting 字段里的广播编号
for (var i = 0; i < team.length; i++) {
var waiting = team[i].waiting || '';
if (waiting.includes(broadcastId) || waiting.includes(devSuffix)) {