guanghulab/scripts/create-standardized-ticket.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

198 lines
7.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// scripts/create-standardized-ticket.js
// 铸渊 · Phase B1 · 标准化工单创建脚本
//
// 将 SYSLOG 写入 Notion 工单队列时使用标准化格式,
// 让 Notion Agent 能够识别和触发后续处理。
//
// 环境变量:
// NOTION_TOKEN Notion API token
// NOTION_TICKET_DB_ID 工单队列数据库 ID
// BROADCAST_ID 广播编号(如 BC-M23-001-AW
// DEVELOPER 开发者信息(如 "DEV-012 Awen"
// SYSLOG_RAW 完整 SYSLOG 原文JSON 字符串或纯文本)
// SUBMIT_TYPE 提交类型syslog / question
// PERSONA_RESULT 人格体处理结果(可选,首次可为空)
// MODULE_VERIFY 模块验证结果 JSON可选
// MODULES_UPLOADED 模块是否全部上传true/false
'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 || '';
const BROADCAST_ID = process.env.BROADCAST_ID || 'UNKNOWN';
const DEVELOPER = process.env.DEVELOPER || process.env.AUTHOR || 'unknown';
const SYSLOG_RAW = process.env.SYSLOG_RAW || process.env.SUBMIT_CONTENT || '';
const SUBMIT_TYPE = process.env.SUBMIT_TYPE || 'syslog';
const PERSONA_RESULT = process.env.PERSONA_RESULT || '';
const MODULE_VERIFY = process.env.MODULE_VERIFY || '';
const MODULES_UPLOADED = process.env.MODULES_UPLOADED || 'false';
const NOTION_VERSION = '2022-06-28';
const NOTION_API_HOSTNAME = 'api.notion.com';
const NOTION_RICH_TEXT_MAX = 2000;
// ══════════════════════════════════════════════════════════
// Notion API 工具
// ══════════════════════════════════════════════════════════
function notionPost(endpoint, body) {
return new Promise(function (resolve, reject) {
var payload = JSON.stringify(body);
var opts = {
hostname: NOTION_API_HOSTNAME,
port: 443,
path: endpoint,
method: 'POST',
headers: {
'Authorization': 'Bearer ' + NOTION_TOKEN,
'Content-Type': 'application/json',
'Notion-Version': NOTION_VERSION,
'Content-Length': Buffer.byteLength(payload),
},
};
var req = https.request(opts, function (res) {
var data = '';
res.on('data', function (chunk) { data += chunk; });
res.on('end', function () {
try {
var parsed = JSON.parse(data);
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(parsed);
} else {
reject(new Error('Notion API ' + res.statusCode + ': ' + (parsed.message || data)));
}
} catch (e) {
reject(new Error('Notion API parse error: ' + data));
}
});
});
req.on('error', reject);
req.write(payload);
req.end();
});
}
function richTextChunks(content) {
var str = String(content || '');
var chunks = [];
for (var i = 0; i < str.length; i += NOTION_RICH_TEXT_MAX) {
chunks.push({ type: 'text', text: { content: str.slice(i, i + NOTION_RICH_TEXT_MAX) } });
}
if (chunks.length === 0) {
chunks.push({ type: 'text', text: { content: '' } });
}
return chunks;
}
// ══════════════════════════════════════════════════════════
// 标准化工单创建
// ══════════════════════════════════════════════════════════
async function createStandardizedTicket() {
if (!NOTION_TOKEN || !NOTION_TICKET_DB_ID) {
console.log('⚠️ Notion credentials not configured, skipping ticket creation');
process.exit(0);
}
var now = new Date().toISOString();
var typeLabel = SUBMIT_TYPE === 'syslog' ? 'SYSLOG处理' : '提问解答';
var ticketStatus = SUBMIT_TYPE === 'syslog' ? '待处理' : '已完成';
var verifyStatus = MODULES_UPLOADED === 'true' ? '模块已验证✅' : '模块待验证⚠️';
var title = '[自动] ' + BROADCAST_ID + ' · ' + typeLabel + ' · ' + verifyStatus;
// Phase B1 标准化字段 — 工单内容
var ticketContent = [
'## 📡 标准化工单 · Phase B1',
'',
'| 字段 | 值 |',
'|------|-----|',
'| 工单类型 | ' + typeLabel + ' |',
'| 状态 | ' + ticketStatus + ' |',
'| 来源 | GitHub Actions |',
'| taskId | ' + BROADCAST_ID + ' |',
'| developer | ' + DEVELOPER + ' |',
'| created_at | ' + now + ' |',
'| retry_count | 0 |',
'| receipt_status | pending |',
'',
];
if (PERSONA_RESULT) {
ticketContent.push('## 铸渊核心大脑处理结果');
ticketContent.push('');
ticketContent.push(PERSONA_RESULT.slice(0, 1500));
ticketContent.push('');
}
ticketContent.push('## 模块上传验证');
ticketContent.push('');
ticketContent.push('模块全部上传: ' + (MODULES_UPLOADED === 'true' ? '✅ 是' : '❌ 否'));
ticketContent.push('');
if (MODULE_VERIFY) {
ticketContent.push('验证详情: ' + MODULE_VERIFY.slice(0, 400));
ticketContent.push('');
}
var contentText = ticketContent.join('\n');
// 构建 Notion 页面
var body = {
parent: { database_id: NOTION_TICKET_DB_ID },
properties: {
'标题': { title: [{ type: 'text', text: { content: title.slice(0, 120) } }] },
'操作类型': { select: { name: '其他' } },
'提交者': { rich_text: [{ type: 'text', text: { content: '铸渊Agent·自动管道' } }] },
'状态': { select: { name: ticketStatus } },
'优先级': { select: { name: 'P1' } },
},
children: [
{
object: 'block',
type: 'paragraph',
paragraph: {
rich_text: richTextChunks(contentText),
},
},
],
};
// 将 SYSLOG 原文作为代码块附加(如果有)
if (SYSLOG_RAW) {
body.children.push({
object: 'block',
type: 'code',
code: {
rich_text: richTextChunks(SYSLOG_RAW.slice(0, 8000)),
language: 'json',
},
});
}
console.log('📋 创建标准化工单...');
console.log(' taskId: ' + BROADCAST_ID);
console.log(' developer: ' + DEVELOPER);
console.log(' type: ' + typeLabel);
console.log(' receipt_status: pending');
try {
var result = await notionPost('/v1/pages', body);
console.log('✅ Notion 标准化工单已创建: ' + result.id);
// 输出工单 ID 到 GITHUB_OUTPUT
var outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, 'ticket_page_id=' + result.id + '\n');
fs.appendFileSync(outputFile, 'ticket_url=' + (result.url || '') + '\n');
}
} catch (err) {
console.error('❌ 工单创建失败: ' + err.message);
process.exit(1);
}
}
createStandardizedTicket();