# ═══════════════════════════════════════════════ # 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 # 📜 Copyright: 国作登字-2026-A-00037559 # ═══════════════════════════════════════════════ name: 📡 SYSLOG Issue Pipeline # 📡 SYSLOG 自助提交系统 · Issue 版全自动闭环 # # 开发者在 GitHub Issue 提交 SYSLOG 或提问(使用 syslog-submit 模板) # → Actions 自动解析 → 模块上传验证 → 调用 LLM API 唤醒人格体 # → 模块闭环测试 → 写入 Notion 工单 → 发邮件给开发者 → Issue 回复 # # 闭环流程: # ① 开发者提交 SYSLOG → Issue 触发 # ② 铸渊 Agent 解析提交内容 # ③ 铸渊 Agent 检测模块是否上传到仓库 # ④ 唤醒铸渊核心大脑认知(注入模块验证结果) # ⑤ 核心大脑处理 SYSLOG + 生成广播 # ⑥ 铸渊 Agent 推送 Notion 工单(触发 Notion 侧处理) # ⑦ 邮件通知开发者 # ⑧ Issue 回复闭环 # # 依赖 Secrets: # LLM_API_KEY 第三方 LLM 平台密钥(必须) # LLM_BASE_URL 第三方 LLM 平台 API 地址(必须,如 https://api.xxx.com/v1) # NOTION_API_TOKEN Notion API token # NOTION_TICKET_DB_ID 霜砚工单数据库 ID # CORE_BRAIN_PAGE_ID 曜冥核心大脑 v4.0 页面 ID(v4.0 协议动态注入) # PORTRAIT_DB_ID 开发者动态画像库数据库 ID(v4.0 协议动态注入) # FINGERPRINT_DB_ID 模块指纹注册表数据库 ID(v4.0 协议动态注入) # SMTP_USER QQ 邮箱地址 # SMTP_PASS QQ 邮箱 SMTP 授权码 on: issues: types: [opened, labeled] jobs: process: name: 📡 处理 SYSLOG 提交 / 广播提问 (Issue) runs-on: ubuntu-latest if: > contains(toJSON(github.event.issue.labels), 'syslog') || contains(github.event.issue.title, 'SYSLOG') || contains(github.event.issue.title, '系统日志') || contains(github.event.issue.body, '### 广播编号') permissions: contents: write issues: write steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci --ignore-scripts - name: 📋 步骤 1/8 · 接收提交 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '1' STEP_NAME: '接收提交' STEP_STATUS: 'ok' STEP_DETAIL: '系统已收到您的 SYSLOG 提交,管道正在运行中…' run: node scripts/pipeline-reporter.js - name: 🔍 Parse submission id: parse uses: actions/github-script@v7 with: script: | const body = context.payload.issue.body || ''; const title = context.payload.issue.title || ''; function extractField(text, label) { const regex = new RegExp('###\\s*' + label + '\\s*\\n+([^\\n#]+)', 'i'); const match = text.match(regex); return match ? match[1].trim() : ''; } const broadcastId = extractField(body, '广播编号') || ''; const submitType = extractField(body, '类型') || ''; const email = extractField(body, '你的邮箱') || ''; const contentMatch = body.match(/###\s*内容\s*\n+([\s\S]*?)$/i); const content = contentMatch ? contentMatch[1].trim() : ''; let type = 'question'; if (submitType.includes('SYSLOG') || title.includes('SYSLOG')) { type = 'syslog'; } else if (submitType.includes('提问') || title.includes('提问')) { type = 'question'; } if (!broadcastId) { core.setFailed('❌ 缺少广播编号,请在提交时填写广播编号'); return; } if (!email) { core.setFailed('❌ 缺少邮箱,请在提交时填写你的邮箱'); return; } if (!content) { core.setFailed('❌ 缺少内容,请粘贴你的 SYSLOG 或问题'); return; } core.setOutput('broadcast_id', broadcastId); core.setOutput('type', type); core.setOutput('email', email); core.setOutput('content', content); core.setOutput('issue_number', context.payload.issue.number); core.setOutput('author', context.payload.issue.user.login); console.log(`📡 解析完成: 广播=${broadcastId}, 类型=${type}, 邮箱=${email}`); - name: 📋 步骤 2/8 · 解析内容(成功) if: success() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '2' STEP_NAME: '解析内容' STEP_STATUS: 'ok' STEP_DETAIL: '广播编号: ${{ steps.parse.outputs.broadcast_id }} · 类型: ${{ steps.parse.outputs.type }} · 邮箱: ${{ steps.parse.outputs.email }}' run: node scripts/pipeline-reporter.js - name: 📋 步骤 2/8 · 解析内容(失败) if: failure() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '2' STEP_NAME: '解析内容' STEP_STATUS: 'error' STEP_DETAIL: '解析失败,请检查提交格式是否正确(需包含广播编号、类型、邮箱、内容)' run: node scripts/pipeline-reporter.js - name: 🔍 铸渊 Agent · 模块上传验证 id: verify env: SYSLOG_CONTENT: ${{ steps.parse.outputs.content }} BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} AUTHOR: ${{ steps.parse.outputs.author }} run: node scripts/verify-modules.js - name: 📋 步骤 3/8 · 模块验证(成功) if: always() && steps.verify.outcome == 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '3' STEP_NAME: '模块验证' STEP_STATUS: 'ok' STEP_DETAIL: '模块上传验证已完成' run: node scripts/pipeline-reporter.js - name: 📋 步骤 3/8 · 模块验证(失败) if: always() && steps.verify.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '3' STEP_NAME: '模块验证' STEP_STATUS: 'error' STEP_DETAIL: '模块验证异常(不影响闭环继续)' run: node scripts/pipeline-reporter.js - name: 🧠 Auto-detect and wake up persona id: persona env: LLM_API_KEY: ${{ secrets.LLM_API_KEY }} LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }} BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} SUBMIT_TYPE: ${{ steps.parse.outputs.type }} SUBMIT_CONTENT: ${{ steps.parse.outputs.content }} AUTHOR: ${{ steps.parse.outputs.author }} MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }} NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }} CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }} PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }} FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }} run: node scripts/wake-persona.js - name: 📋 步骤 4/8 · 唤醒核心大脑(成功) if: success() env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '4' STEP_NAME: '唤醒核心大脑' STEP_STATUS: 'ok' STEP_DETAIL: '铸渊核心大脑已完成处理' run: node scripts/pipeline-reporter.js - name: 📋 步骤 4/8 · 唤醒核心大脑(失败) if: failure() && steps.parse.outcome == 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '4' STEP_NAME: '唤醒核心大脑' STEP_STATUS: 'error' STEP_DETAIL: 'API 调用失败,请检查 Secrets: LLM_API_KEY / LLM_BASE_URL 是否配置正确' run: node scripts/pipeline-reporter.js # ✅ 修复点:原来是 if: $ secrets.NOTION_API_TOKEN ,会报 Unrecognized named-value: 'secrets' # secrets 不能在 if: 里直接用,必须改成 != '' 的形式 - name: 📋 创建标准化 Notion 工单(Phase B1) id: ticket if: ${{ secrets.NOTION_API_TOKEN != '' }} env: NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }} NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }} BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} SUBMIT_TYPE: ${{ steps.parse.outputs.type }} PERSONA_RESULT: ${{ steps.persona.outputs.result }} MODULE_VERIFY: ${{ steps.verify.outputs.verify_result }} MODULES_UPLOADED: ${{ steps.verify.outputs.modules_uploaded }} DEVELOPER: ${{ steps.parse.outputs.author }} SYSLOG_RAW: ${{ steps.parse.outputs.content }} run: node scripts/create-standardized-ticket.js - name: 📋 步骤 5/8 · 创建 Notion 工单(成功) if: always() && steps.ticket.outcome == 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '5' STEP_NAME: '创建 Notion 工单' STEP_STATUS: 'ok' STEP_DETAIL: '已写入霜砚工单簿' run: node scripts/pipeline-reporter.js - name: 📋 步骤 5/8 · 创建 Notion 工单(跳过) if: always() && steps.ticket.outcome == 'skipped' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '5' STEP_NAME: '创建 Notion 工单' STEP_STATUS: 'skip' STEP_DETAIL: 'Notion Token 未配置,跳过' run: node scripts/pipeline-reporter.js - name: 📋 步骤 5/8 · 创建 Notion 工单(失败) if: always() && steps.ticket.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '5' STEP_NAME: '创建 Notion 工单' STEP_STATUS: 'error' STEP_DETAIL: 'Notion API 写入失败' run: node scripts/pipeline-reporter.js - name: 📡 推送广播到 GitHub(Phase B4) id: broadcast if: steps.persona.outcome == 'success' && steps.parse.outputs.type == 'syslog' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} DEVELOPER_NAME: ${{ steps.parse.outputs.author }} BROADCAST_CONTENT: ${{ steps.persona.outputs.result }} run: node scripts/push-broadcast-to-github.js - name: 📋 步骤 6/8 · 生成广播(成功) if: always() && steps.broadcast.outcome == 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '6' STEP_NAME: '生成广播' STEP_STATUS: 'ok' STEP_DETAIL: '新广播已生成并推送' run: node scripts/pipeline-reporter.js - name: 📋 步骤 6/8 · 生成广播(跳过) if: always() && steps.broadcast.outcome == 'skipped' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '6' STEP_NAME: '生成广播' STEP_STATUS: 'skip' STEP_DETAIL: '非 SYSLOG 类型或上游步骤未成功,跳过广播生成' run: node scripts/pipeline-reporter.js - name: 📋 步骤 6/8 · 生成广播(失败) if: always() && steps.broadcast.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '6' STEP_NAME: '生成广播' STEP_STATUS: 'error' STEP_DETAIL: '广播生成或推送失败' run: node scripts/pipeline-reporter.js - name: 📧 Send email to developer id: email env: SMTP_USER: ${{ secrets.SMTP_USER }} SMTP_PASS: ${{ secrets.SMTP_PASS }} EMAIL_TO: ${{ steps.parse.outputs.email }} BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} SUBMIT_TYPE: ${{ steps.parse.outputs.type }} PERSONA_RESULT: ${{ steps.persona.outputs.result }} run: | node -e " const nodemailer = require('nodemailer'); const user = process.env.SMTP_USER || ''; const pass = process.env.SMTP_PASS || ''; const to = process.env.EMAIL_TO || ''; const broadcastId = process.env.BROADCAST_ID || ''; const type = process.env.SUBMIT_TYPE || 'syslog'; const result = process.env.PERSONA_RESULT || '(处理中,请稍后)'; if (!user || !pass) { console.log('⚠️ SMTP not configured, skipping email'); process.exit(0); } if (!to) { console.log('⚠️ No recipient email, skipping'); process.exit(0); } const subjectText = type === 'syslog' ? '[光湖系统] ' + broadcastId + ' · 新广播已生成' : '[光湖系统] ' + broadcastId + ' · 问题已解答'; const resultHtml = result .replace(/&/g, '&') .replace(//g, '>') .replace(/\n/g, '
'); const html = [ '
', '
', '

🌊 光湖系统 · 自动通知

', '

HoloLake · 人格语言操作系统

', '
', '
', '

📡 ' + broadcastId + '

', '
' + resultHtml + '
', '
', '
', '↩ 回到仓库继续开发', '

🌀 铸渊 · 代码守护人格体 · 自动发送

', '
', '
' ].join('\n'); const transporter = nodemailer.createTransport({ host: 'smtp.qq.com', port: 465, secure: true, auth: { user, pass } }); transporter.sendMail({ from: '\"光湖系统\" <' + user + '>', to: to, subject: subjectText, html: html }).then((info) => { console.log('✅ 邮件已发送: ' + info.messageId); }).catch((err) => { console.log('⚠️ 邮件发送失败: ' + err.message); }); " - name: 📋 步骤 7/8 · 邮件通知(成功) if: always() && steps.email.outcome == 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '7' STEP_NAME: '邮件通知' STEP_STATUS: 'ok' STEP_DETAIL: '邮件通知步骤已执行' run: node scripts/pipeline-reporter.js - name: 📋 步骤 7/8 · 邮件通知(失败) if: always() && steps.email.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE_NUMBER: ${{ github.event.issue.number }} STEP_NUM: '7' STEP_NAME: '邮件通知' STEP_STATUS: 'error' STEP_DETAIL: '邮件发送失败,请检查 Secrets: SMTP_USER / SMTP_PASS' run: node scripts/pipeline-reporter.js - name: 💬 Reply to Issue uses: actions/github-script@v7 with: script: | const number = context.payload.issue.number; const type = '${{ steps.parse.outputs.type }}'; const broadcastId = '${{ steps.parse.outputs.broadcast_id }}'; const email = '${{ steps.parse.outputs.email }}'; const modulesUploaded = '${{ steps.verify.outputs.modules_uploaded }}' === 'true'; const moduleCount = '${{ steps.verify.outputs.module_count }}' || '0'; const typeLabel = type === 'syslog' ? 'SYSLOG 闭环处理' : '问题解答'; const maskedEmail = email.length > 4 ? email.replace(/(.{2})(.*)(@.*)/, '$1***$3') : '***'; const moduleStatus = moduleCount === '0' ? 'ℹ️ 未检测到模块引用' : (modulesUploaded ? '✅ 全部已上传' : '⚠️ 部分模块未上传'); const body = [ '## 🎉 闭环处理完成 · ' + typeLabel, '', '| 项目 | 内容 |', '|------|------|', '| 📡 广播编号 | `' + broadcastId + '` |', '| 🔍 模块验证 | ' + moduleStatus + ' |', '| 📧 结果发送至 | `' + maskedEmail + '` |', '| 🤖 处理人格体 | 铸渊 |', '| ⏰ 处理时间 | ' + new Date().toISOString() + ' |', '', '> 铸渊核心大脑已完成 SYSLOG 验收 + 模块检测 + 广播生成。', '> 结果已发送到你的邮箱,Notion 侧工单已创建。', '>', '> 如未收到邮件,请检查垃圾箱或重新提交。', '>', '> *—— 铸渊(ICE-GL-ZY001)· 代码守护人格体*' ].join('\n'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: number, body: body }); await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: number, state: 'closed', labels: ['syslog', 'processed'] }); console.log('✅ Issue 回复已发送并已关闭'); - name: 🔴 失败告警 if: failure() uses: actions/github-script@v7 with: script: | const number = context.payload.issue?.number; if (!number) return; const actionsUrl = 'https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions'; try { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: number, body: '## ⚠️ 闭环处理异常\n\n❌ **处理失败** · 请检查提交格式是否正确,或联系管理员。\n\n> 部分步骤异常,已记录日志。冰朔会在下次巡检时处理。\n> 错误详情请查看 [Actions 日志](' + actionsUrl + ')。\n>\n> *—— 铸渊(ICE-GL-ZY001)*' }); } catch (err) { console.log('⚠️ 失败告警回复失败: ' + err.message); }