From 8fde49d134b9f31f0b6cb47d2ef8e9ec5b590ff8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Mar 2026 04:58:33 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=80=85=E5=85=A5=E5=8F=A3404=20-=20=E4=BB=8EDiscussions?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=88=B0Issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Discussions未启用导致开发者入口两个按钮404。 - 创建 SYSLOG Issue 模板替代不可用的 Discussion 模板 - 修复 README 开发者入口链接指向 Issues - 创建 Issue 版本的 SYSLOG 自动管道工作流 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/syslog-submit.yml | 54 ++++ .github/workflows/syslog-issue-pipeline.yml | 325 ++++++++++++++++++++ README.md | 8 +- 3 files changed, 383 insertions(+), 4 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/syslog-submit.yml create mode 100644 .github/workflows/syslog-issue-pipeline.yml diff --git a/.github/ISSUE_TEMPLATE/syslog-submit.yml b/.github/ISSUE_TEMPLATE/syslog-submit.yml new file mode 100644 index 00000000..80a87d27 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/syslog-submit.yml @@ -0,0 +1,54 @@ +name: "📡 提交系统日志 / 提问" +description: "做完了?提交你的 SYSLOG。有问题?在这里提问。" +title: "BC-XXX-XXX|SYSLOG" +labels: ["syslog", "pending"] +assignees: [] +body: + - type: markdown + attributes: + value: | + ## 📡 SYSLOG 自助提交 / 广播提问 + + > 做完了?把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 + > + > 有问题?把问题粘贴进去,填上邮箱,点提交。解答会发到你邮箱里。 + + **标题格式**:`BC-XXX-XXX|SYSLOG` 或 `BC-XXX-XXX|提问` + + - type: input + id: broadcast_id + attributes: + label: "广播编号" + description: "写上你当前广播的编号,例如 BC-M22-009-AW" + placeholder: "BC-M22-009-AW" + validations: + required: true + + - type: dropdown + id: submit_type + attributes: + label: "类型" + description: "选择提交类型" + options: + - SYSLOG + - 提问 + validations: + required: true + + - type: input + id: email + attributes: + label: "你的邮箱" + description: "用于接收新广播或问题解答" + placeholder: "your@email.com" + validations: + required: true + + - type: textarea + id: content + attributes: + label: "内容" + description: "粘贴你的 SYSLOG 全文 或 问题描述" + placeholder: "在这里粘贴你的 SYSLOG 或问题..." + validations: + required: true diff --git a/.github/workflows/syslog-issue-pipeline.yml b/.github/workflows/syslog-issue-pipeline.yml new file mode 100644 index 00000000..5a5d81a5 --- /dev/null +++ b/.github/workflows/syslog-issue-pipeline.yml @@ -0,0 +1,325 @@ +name: SYSLOG Issue Pipeline +# 📡 SYSLOG 自助提交系统 · Issue 版全自动闭环 +# +# 开发者在 GitHub Issue 提交 SYSLOG 或提问(使用 syslog-submit 模板) +# → Actions 自动解析 → 调用 LLM API 唤醒人格体 +# → 写入 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') + 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: 🔍 Parse submission + id: parse + uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const title = context.payload.issue.title || ''; + + // Parse structured fields from issue body + function extractField(text, label) { + // Match form field format: ### Label\n\nValue + 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, '你的邮箱') || ''; + + // Extract content (everything after "### 内容") + const contentMatch = body.match(/###\s*内容\s*\n+([\s\S]*?)$/i); + const content = contentMatch ? contentMatch[1].trim() : ''; + + // Determine type from title or body + let type = 'question'; // default + if (submitType.includes('SYSLOG') || title.includes('SYSLOG')) { + type = 'syslog'; + } else if (submitType.includes('提问') || title.includes('提问')) { + type = 'question'; + } + + // Validate + 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: 🧠 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 }} + 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: 📋 Write to Notion 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 }} + run: | + node -e " + const https = require('https'); + + const token = process.env.NOTION_TOKEN; + const dbId = process.env.NOTION_TICKET_DB_ID; + const broadcastId = process.env.BROADCAST_ID || 'UNKNOWN'; + const type = process.env.SUBMIT_TYPE || 'syslog'; + const result = process.env.PERSONA_RESULT || '(no result)'; + + if (!token || !dbId) { + console.log('⚠️ Notion credentials not configured, skipping ticket creation'); + process.exit(0); + } + + const typeLabel = type === 'syslog' ? 'SYSLOG闭环' : '提问解答'; + const title = '[自动] ' + broadcastId + ' · ' + typeLabel; + + const body = JSON.stringify({ + parent: { database_id: dbId }, + properties: { + '标题': { title: [{ type: 'text', text: { content: title.slice(0, 120) } }] }, + '操作类型': { select: { name: '其他' } }, + '提交者': { rich_text: [{ type: 'text', text: { content: '自动管道' } }] }, + '状态': { select: { name: '已完成' } }, + '优先级': { select: { name: 'P1' } } + }, + children: [{ + object: 'block', + type: 'paragraph', + paragraph: { + rich_text: [{ type: 'text', text: { content: result.slice(0, 2000) } }] + } + }] + }); + + const opts = { + hostname: 'api.notion.com', + port: 443, + path: '/v1/pages', + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + token, + 'Content-Type': 'application/json', + 'Notion-Version': '2022-06-28', + 'Content-Length': Buffer.byteLength(body) + } + }; + + const req = https.request(opts, (res) => { + let data = ''; + res.on('data', (c) => data += c); + res.on('end', () => { + if (res.statusCode >= 200 && res.statusCode < 300) { + console.log('✅ Notion 工单已创建'); + } else { + console.log('⚠️ Notion 工单创建失败: ' + res.statusCode + ' ' + data); + } + }); + }); + req.on('error', (e) => console.log('⚠️ Notion 请求失败: ' + e.message)); + req.write(body); + req.end(); + " + + - name: 📧 Send email to developer + 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: 💬 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 typeLabel = type === 'syslog' ? 'SYSLOG 闭环处理' : '问题解答'; + const maskedEmail = email.length > 4 + ? email.replace(/(.{2})(.*)(@.*)/, '$1***$3') + : '***'; + + const body = [ + '✅ **已处理** · ' + typeLabel, + '', + '| 项目 | 内容 |', + '|------|------|', + '| 📡 广播编号 | `' + broadcastId + '` |', + '| 📧 结果发送至 | `' + maskedEmail + '` |', + '| 🤖 处理人格体 | 铸渊 |', + '| ⏰ 处理时间 | ' + new Date().toISOString() + ' |', + '', + '> 结果已发送到你的邮箱,请查收。', + '>', + '> 如未收到,请检查垃圾箱或重新提交。' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + body: body + }); + + // Close the issue after processing + 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; + + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + body: '❌ **处理失败** · 请检查提交格式是否正确,或联系管理员。\n\n> 错误详情请查看 [Actions 日志](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions)。' + }); + } catch (err) { + console.log('⚠️ 失败告警回复失败: ' + err.message); + } diff --git a/README.md b/README.md index 4f27b893..37a671ef 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,12 @@
-[![提交系统日志](https://img.shields.io/badge/📡_提交系统日志-点这里-blue?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区) -[![遇到问题](https://img.shields.io/badge/❓_遇到问题-点这里提问-green?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区) +[![提交系统日志](https://img.shields.io/badge/📡_提交系统日志-点这里-blue?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=syslog-submit.yml) +[![遇到问题](https://img.shields.io/badge/❓_遇到问题-点这里提问-green?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=dev-question.yml) -> 做完了?把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 +> 做完了?点蓝色按钮,把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 > -> 有问题?同一个入口,选「提问」,问题解答也发到你邮箱里。 +> 有问题?点绿色按钮,填写问题描述,铸渊会自动回答你。