# ═══════════════════════════════════════════════ # 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 # 📜 Copyright: 国作登字-2026-A-00037559 # ═══════════════════════════════════════════════ name: 铸渊 · SYSLOG Pipeline (A/D/E) on: push: branches: [main] paths: - 'syslog-inbox/**' workflow_run: workflows: ["铸渊 · 飞书SYSLOG桥接"] types: [completed] workflow_dispatch: jobs: # ── Pipeline A:SYSLOG 读取与处理 ────────────────────── pipeline-a-syslog: name: 📥 Pipeline A · SYSLOG 读取处理 if: >- github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest permissions: contents: write issues: read outputs: processed_count: ${{ steps.process.outputs.processed_count }} has_syslog: ${{ steps.parse.outputs.has_syslog }} sender_open_id: ${{ steps.parse.outputs.sender_open_id }} chat_id: ${{ steps.parse.outputs.chat_id }} sender_name: ${{ steps.parse.outputs.sender_name }} syslog_file: ${{ steps.parse.outputs.syslog_file }} steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} ref: main - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci # Step 0: 解析 sender 信息(在 process-syslog.js 归档之前) - name: 📋 解析 SYSLOG sender 信息 id: parse run: | LATEST=$(ls -t syslog-inbox/*.json 2>/dev/null | grep -v '.gitkeep' | head -1 || true) if [ -z "$LATEST" ]; then echo "📭 syslog-inbox/ 无待处理文件" echo "has_syslog=false" >> "$GITHUB_OUTPUT" exit 0 fi echo "has_syslog=true" >> "$GITHUB_OUTPUT" echo "syslog_file=$LATEST" >> "$GITHUB_OUTPUT" SENDER_OPEN_ID=$(jq -r '.sender_open_id // .sender_id // empty' "$LATEST" 2>/dev/null || true) CHAT_ID=$(jq -r '.chat_id // empty' "$LATEST" 2>/dev/null || true) SENDER_NAME=$(jq -r '.sender_name // empty' "$LATEST" 2>/dev/null || true) echo "sender_open_id=$SENDER_OPEN_ID" >> "$GITHUB_OUTPUT" echo "chat_id=$CHAT_ID" >> "$GITHUB_OUTPUT" echo "sender_name=$SENDER_NAME" >> "$GITHUB_OUTPUT" echo "📋 SYSLOG 文件: $LATEST" echo " sender_open_id: ${SENDER_OPEN_ID:-无}" echo " chat_id: ${CHAT_ID:-无}" echo " sender_name: ${SENDER_NAME:-无}" # Step 1: 写入 Notion SYSLOG 收件箱 - name: 📝 写入 Notion SYSLOG 收件箱 if: steps.parse.outputs.has_syslog == 'true' env: NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }} NOTION_DB_SYSLOG: ${{ secrets.ZY_NOTION_SYSLOG_DB }} run: node scripts/write-notion-syslog.js "${{ steps.parse.outputs.syslog_file }}" # Step 2: 处理 syslog-inbox 条目(归档到 syslog-processed/) - name: 📥 处理 syslog-inbox 条目 id: process run: | node scripts/process-syslog.js COUNT=$(ls syslog-processed/ -R 2>/dev/null | grep -c '\.json' || echo 0) echo "processed_count=$COUNT" >> "$GITHUB_OUTPUT" - name: 提交处理结果 run: | git config user.name "铸渊[bot]" git config user.email "zhu-yuan-bot@guanghulab.com" git add syslog-inbox/ syslog-processed/ .github/brain/memory.json git diff --staged --quiet || git commit -m "📥 syslog: 处理 inbox 条目,更新大脑记忆 [skip ci]" git push # ── Pipeline B:Claude API 唤醒人格体 ──────────────────── pipeline-b-persona: name: 🧠 Pipeline B · 人格体唤醒 runs-on: ubuntu-latest needs: pipeline-a-syslog if: needs.pipeline-a-syslog.outputs.has_syslog == 'true' permissions: contents: read outputs: broadcast_title: ${{ steps.persona.outputs.broadcast_title }} broadcast_url: ${{ steps.persona.outputs.broadcast_url }} steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} ref: main - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: 🧠 唤醒人格体处理 SYSLOG id: persona env: LLM_API_KEY: ${{ secrets.ZY_LLM_API_KEY }} LLM_BASE_URL: ${{ secrets.ZY_LLM_BASE_URL }} NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }} CORE_BRAIN_PAGE_ID: ${{ secrets.ZY_NOTION_BRAIN_PAGE }} PORTRAIT_DB_ID: ${{ secrets.ZY_NOTION_PORTRAIT_DB }} FINGERPRINT_DB_ID: ${{ secrets.ZY_NOTION_FINGERPRINT_DB }} SUBMIT_TYPE: syslog SYSLOG_FILE: ${{ needs.pipeline-a-syslog.outputs.syslog_file }} AUTHOR: ${{ needs.pipeline-a-syslog.outputs.sender_name }} run: | if [ -z "$LLM_API_KEY" ] || [ -z "$LLM_BASE_URL" ]; then echo "⚠️ LLM_API_KEY 或 LLM_BASE_URL 未配置,跳过人格体唤醒" echo "broadcast_title=" >> "$GITHUB_OUTPUT" echo "broadcast_url=" >> "$GITHUB_OUTPUT" exit 0 fi # 读取 SYSLOG 文件内容传递给 wake-persona.js # 注意:Pipeline A 可能已将文件从 syslog-inbox/ 归档到 syslog-processed/ if [ -f "$SYSLOG_FILE" ]; then export SUBMIT_CONTENT=$(cat "$SYSLOG_FILE") else BASENAME=$(basename "$SYSLOG_FILE") PROCESSED_FILE=$(find syslog-processed/ -name "$BASENAME" -type f 2>/dev/null | head -1) if [ -n "$PROCESSED_FILE" ]; then echo "📂 文件已归档,从 $PROCESSED_FILE 读取" export SUBMIT_CONTENT=$(cat "$PROCESSED_FILE") else echo "⚠️ SYSLOG 文件未找到: $SYSLOG_FILE(inbox 和 processed 均不存在)" fi fi if [ -z "$SUBMIT_CONTENT" ]; then echo "⚠️ SUBMIT_CONTENT 为空,跳过人格体唤醒" echo "broadcast_title=" >> "$GITHUB_OUTPUT" echo "broadcast_url=" >> "$GITHUB_OUTPUT" exit 0 fi if node scripts/wake-persona.js; then echo "✅ 人格体唤醒成功" else echo "⚠️ 人格体唤醒失败(exit code: $?),继续后续步骤" fi # 读取人格体输出的广播信息(如果有) if [ -f /tmp/broadcast-result.json ]; then BROADCAST_TITLE=$(jq -r '.title // empty' /tmp/broadcast-result.json) BROADCAST_URL=$(jq -r '.notion_url // empty' /tmp/broadcast-result.json) echo "broadcast_title=$BROADCAST_TITLE" >> "$GITHUB_OUTPUT" echo "broadcast_url=$BROADCAST_URL" >> "$GITHUB_OUTPUT" echo "✅ 人格体处理完成,广播标题: $BROADCAST_TITLE" else echo "⚠️ /tmp/broadcast-result.json 未生成(人格体可能未产出广播)" echo "broadcast_title=" >> "$GITHUB_OUTPUT" echo "broadcast_url=" >> "$GITHUB_OUTPUT" fi # ── Pipeline C:推送广播到飞书 ─────────────────────────── pipeline-c-push: name: 📢 Pipeline C · 飞书广播推送 runs-on: ubuntu-latest needs: [pipeline-a-syslog, pipeline-b-persona] permissions: {} if: >- needs.pipeline-b-persona.outputs.broadcast_title != '' && (needs.pipeline-a-syslog.outputs.chat_id != '' || needs.pipeline-a-syslog.outputs.sender_open_id != '') steps: - name: 📢 推送广播到飞书 env: PUSH_URL: https://guanghulab.com/webhook/push-broadcast PUSH_TOKEN: ${{ secrets.ZY_PUSH_TOKEN }} CHAT_ID: ${{ needs.pipeline-a-syslog.outputs.chat_id }} SENDER_OPEN_ID: ${{ needs.pipeline-a-syslog.outputs.sender_open_id }} BROADCAST_TITLE: ${{ needs.pipeline-b-persona.outputs.broadcast_title }} BROADCAST_URL: ${{ needs.pipeline-b-persona.outputs.broadcast_url }} run: | if [ -z "$PUSH_TOKEN" ]; then echo "⚠️ PUSH_BROADCAST_TOKEN 未配置,跳过飞书推送" exit 0 fi echo "📢 推送广播到飞书..." echo " 标题: $BROADCAST_TITLE" echo " 目标: ${CHAT_ID:-$SENDER_OPEN_ID}" HTTP_CODE=$(curl -s -o /tmp/push-response.txt -w "%{http_code}" \ -X POST "$PUSH_URL" \ -H "Content-Type: application/json" \ -H "x-push-token: $PUSH_TOKEN" \ -d "$(jq -n \ --arg chat_id "$CHAT_ID" \ --arg sender_open_id "$SENDER_OPEN_ID" \ --arg broadcast_title "$BROADCAST_TITLE" \ --arg broadcast_content "人格体已验收,请查看完整广播。" \ --arg broadcast_url "$BROADCAST_URL" \ '{chat_id: $chat_id, sender_open_id: $sender_open_id, broadcast_title: $broadcast_title, broadcast_content: $broadcast_content, broadcast_url: $broadcast_url}')") echo " HTTP 响应: $HTTP_CODE" cat /tmp/push-response.txt 2>/dev/null || true echo "" if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then echo "✅ 广播已推送到飞书" else echo "❌ 推送失败 (HTTP $HTTP_CODE),可通过 push-broadcast-feishu workflow 手动补推" fi # ── Pipeline D:Issues 巡检 ───────────────────────────── pipeline-d-issues: name: 🔍 Pipeline D · Issues 巡检 runs-on: ubuntu-latest needs: pipeline-a-syslog permissions: contents: write issues: read steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} ref: main - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: 🔍 巡检 Issues env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} run: | echo "🔍 Pipeline D · Issues 巡检开始" node -e " const https = require('https'); const token = process.env.GITHUB_TOKEN; const repo = process.env.REPO; const opts = { hostname: 'api.github.com', path: '/repos/' + repo + '/issues?state=open&per_page=20', headers: { 'Authorization': 'Bearer ' + token, 'User-Agent': 'zhuyuan-bot' } }; https.get(opts, res => { let body = ''; res.on('data', c => body += c); res.on('end', () => { const issues = JSON.parse(body); console.log('📋 开放 Issues 数量:' + (Array.isArray(issues) ? issues.length : '读取失败')); if (Array.isArray(issues) && issues.length > 0) { issues.slice(0, 5).forEach(i => console.log(' #' + i.number + ' ' + i.title)); } console.log('✅ Pipeline D 巡检完成'); }); }).on('error', e => { console.error('❌ 巡检失败:', e.message); process.exit(1); }); " # ── Pipeline E:变更感知 ──────────────────────────────── pipeline-e-changes: name: 📡 Pipeline E · 变更感知 runs-on: ubuntu-latest needs: pipeline-a-syslog permissions: contents: write steps: - uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} ref: main fetch-depth: 10 - name: 📡 感知近期变更 run: | echo "📡 Pipeline E · 变更感知开始" echo "=== 近期 10 次提交 ===" git --no-pager log --oneline -10 echo "" echo "=== syslog-inbox 文件状态 ===" ls -la syslog-inbox/ || echo "(空)" echo "" echo "=== syslog-processed 文件状态 ===" ls -laR syslog-processed/ || echo "(空)" echo "✅ Pipeline E 变更感知完成" # ━━━ 🧬 双端神经系统·自报告 ━━━ - name: "🧬 写入神经自报告" if: always() run: | WORKFLOW_ID="syslog" BRAIN="SY-03" REPORT_DIR="data/neural-reports/syslog" TIMESTAMP=$(TZ=Asia/Shanghai date +%Y-%m-%d-%H%M) STATUS="${{ job.status }}" mkdir -p "$REPORT_DIR" cat > "${REPORT_DIR}/${WORKFLOW_ID}-${TIMESTAMP}.json" << EOF { "workflow_id": "${WORKFLOW_ID}", "run_id": "${{ github.run_id }}", "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", "status": "${STATUS}", "brain": "${BRAIN}", "event": "${{ github.event_name }}", "branch": "${{ github.ref_name }}", "commit": "${{ github.sha }}" } EOF git config user.name "zhuyuan-bot" git config user.email "zhuyuan@guanghulab.com" git add "$REPORT_DIR/" git diff --cached --quiet || \ git commit -m "🧬 ${WORKFLOW_ID} 自报告 · ${TIMESTAMP} [skip ci]" git push || echo "⚠️ 自报告push失败(不阻断主流程)" # ━━━ 📡 指令回执·自动同步 ━━━ - name: "📡 同步回执到 Notion" if: always() env: NOTION_API_KEY: ${{ secrets.ZY_NOTION_TOKEN }} RECEIPT_DB_ID: ${{ secrets.ZY_NOTION_RECEIPT_DB }} run: | node scripts/neural/write-receipt-to-notion.js \ --instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \ --status "${{ job.status }}" \ --workflow "syslog" \ --summary "syslog 自动执行" \ --related-agent "SY-03"