zhizhi/scripts/create-standardized-ticket.js

198 lines
7.0 KiB
JavaScript
Raw Normal View History

// 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 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) {
var fs = require('fs');
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();