190 lines
8.8 KiB
YAML
190 lines
8.8 KiB
YAML
name: "🦅 铸渊·天眼 · 全局俯瞰 + 自动诊断 + 修复驱动"
|
||
|
||
on:
|
||
schedule:
|
||
- cron: '0 22 * * *' # UTC 22:00 = 北京 06:00
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: write
|
||
issues: write
|
||
actions: read
|
||
|
||
jobs:
|
||
skyeye:
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 30
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '20'
|
||
|
||
- name: "🧠 Phase 1 · 唤醒核心大脑"
|
||
id: brain
|
||
run: |
|
||
echo "[GH-WF-RUN-SKYEYE] 🦅 天眼启动 · $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||
BRAIN_OK=true
|
||
for f in memory.json routing-map.json dev-status.json; do
|
||
if [ -f ".github/persona-brain/$f" ]; then
|
||
python3 -c "import json; json.load(open('.github/persona-brain/$f'))" 2>/dev/null \
|
||
&& echo "✅ $f 完整" || { echo "❌ $f 损坏"; BRAIN_OK=false; }
|
||
else
|
||
echo "❌ $f 缺失"; BRAIN_OK=false
|
||
fi
|
||
done
|
||
echo "🌊 加载光湖存在级安全协议..."
|
||
if [ -f ".github/persona-brain/security-protocol.json" ]; then
|
||
PROTOCOL_LEVEL=$(cat .github/persona-brain/security-protocol.json | python3 -c "import sys,json; print(json.load(sys.stdin)['level'])")
|
||
echo "✅ 安全协议已加载 · 等级: ${PROTOCOL_LEVEL}"
|
||
else
|
||
echo "❌ 安全协议缺失!创建工单!"
|
||
fi
|
||
echo "brain_ok=$BRAIN_OK" >> $GITHUB_OUTPUT
|
||
|
||
- name: "📡 Phase 1.6 · 拉取 Agent 集群公告板"
|
||
env:
|
||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
|
||
run: |
|
||
echo "[BRIDGE-BULLETIN-READ] 🔄 拉取 Agent 集群公告板"
|
||
node scripts/skyeye/bulletin-board.js > /tmp/skyeye/bulletin-board.json || echo "{}" > /tmp/skyeye/bulletin-board.json
|
||
|
||
- name: "🦅 Phase 2 · 全局扫描"
|
||
id: scan
|
||
env:
|
||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||
SMTP_PASS: ${{ secrets.SMTP_PASS }}
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
mkdir -p /tmp/skyeye
|
||
node scripts/skyeye/scan-workflows.js > /tmp/skyeye/workflow-health.json
|
||
gh run list --limit 50 --json name,status,conclusion,createdAt,updatedAt \
|
||
> /tmp/skyeye/recent-runs.json || { echo "⚠️ gh run list 失败,使用空列表" && echo "[]" > /tmp/skyeye/recent-runs.json; }
|
||
FAILED_COUNT=$(cat /tmp/skyeye/recent-runs.json | \
|
||
python3 -c "import sys,json; runs=json.load(sys.stdin); print(sum(1 for r in runs if r.get('conclusion')=='failure'))" 2>/dev/null || echo "0")
|
||
echo "failed_count=$FAILED_COUNT" >> $GITHUB_OUTPUT
|
||
node scripts/skyeye/scan-structure.js > /tmp/skyeye/structure-health.json
|
||
node scripts/skyeye/scan-brain-health.js > /tmp/skyeye/brain-health.json
|
||
node scripts/skyeye/scan-external-bridges.js > /tmp/skyeye/bridge-health.json
|
||
node scripts/skyeye/scan-security-protocol.js > /tmp/skyeye/security-health.json
|
||
node scripts/commander-dashboard.js > /dev/null 2>&1 || true
|
||
node scripts/skyeye/scan-bulletin-sfp.js > /tmp/skyeye/sfp-health.json
|
||
node scripts/skyeye/scan-soldier-health.js > /tmp/skyeye/soldier-health.json
|
||
|
||
- name: "🔬 Phase 3 · 诊断"
|
||
id: diagnose
|
||
run: |
|
||
node scripts/skyeye/diagnose.js > /tmp/skyeye/diagnosis.json
|
||
ISSUES_COUNT=$(cat /tmp/skyeye/diagnosis.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('total_issues', 0))" 2>/dev/null || echo "0")
|
||
AUTO_FIXABLE=$(cat /tmp/skyeye/diagnosis.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('auto_fixable', 0))" 2>/dev/null || echo "0")
|
||
NEEDS_HUMAN=$(cat /tmp/skyeye/diagnosis.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('needs_human', 0))" 2>/dev/null || echo "0")
|
||
echo "issues_count=$ISSUES_COUNT" >> $GITHUB_OUTPUT
|
||
echo "auto_fixable=$AUTO_FIXABLE" >> $GITHUB_OUTPUT
|
||
echo "needs_human=$NEEDS_HUMAN" >> $GITHUB_OUTPUT
|
||
|
||
- name: "🔄 Phase 3.5 · ASOP 自优化审批"
|
||
run: |
|
||
echo "[GH-ASOP-APPROVE] 🔄 ASOP 审批引擎启动..."
|
||
node scripts/skyeye/asop-reviewer.js > /tmp/skyeye/asop-review.json || echo "{}" > /tmp/skyeye/asop-review.json
|
||
|
||
- name: "🔧 Phase 4 · 修复Agent"
|
||
if: steps.diagnose.outputs.auto_fixable != '0'
|
||
env:
|
||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
node scripts/skyeye/repair-agent.js
|
||
git config user.name "zhuyuan-bot"
|
||
git config user.email "zhuyuan@guanghulab.com"
|
||
git add -A
|
||
if ! git diff --cached --quiet; then
|
||
git commit -m "🦅 天眼·修复Agent · $(date +%Y-%m-%d) · 自动修复${{ steps.diagnose.outputs.auto_fixable }}个问题"
|
||
git push
|
||
fi
|
||
|
||
- name: "🔄 Phase 5 · 重新触发失败的 Workflow"
|
||
if: steps.scan.outputs.failed_count != '0'
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
FAILED_WORKFLOWS=$(cat /tmp/skyeye/recent-runs.json | \
|
||
python3 -c "
|
||
import sys, json
|
||
runs = json.load(sys.stdin)
|
||
failed = set()
|
||
for r in runs:
|
||
if r.get('conclusion') == 'failure':
|
||
failed.add(r['name'])
|
||
for w in failed:
|
||
print(w)
|
||
" 2>/dev/null || true)
|
||
echo "需要重新触发的 Workflow:"
|
||
echo "$FAILED_WORKFLOWS"
|
||
# 记录到报告,具体重触发逻辑由各 workflow 自带的 workflow_dispatch 支持
|
||
|
||
- name: "🔧 Phase 5.5 · ASOP 执行已批准优化"
|
||
run: |
|
||
echo "[GH-ASOP-EXECUTE] 🔧 ASOP 执行器启动..."
|
||
node scripts/skyeye/asop-executor.js > /tmp/skyeye/asop-execute.json || echo "{}" > /tmp/skyeye/asop-execute.json
|
||
|
||
- name: "🔍 Phase 5.7 · ASOP 验证优化效果"
|
||
run: |
|
||
echo "[GH-ASOP-EXECUTE] 🔍 ASOP 验证器启动..."
|
||
node scripts/skyeye/asop-verifier.js > /tmp/skyeye/asop-verify.json || echo "{}" > /tmp/skyeye/asop-verify.json
|
||
|
||
- name: "📋 Phase 6 · 全局健康报告"
|
||
run: |
|
||
node scripts/skyeye/report-generator.js
|
||
mkdir -p data/skyeye-reports
|
||
DATE=$(date +%Y-%m-%d)
|
||
cp /tmp/skyeye/full-report.json "data/skyeye-reports/skyeye-${DATE}.json"
|
||
git config user.name "zhuyuan-bot"
|
||
git config user.email "zhuyuan@guanghulab.com"
|
||
git add data/skyeye-reports/ .github/persona-brain/memory.json data/asop-requests/
|
||
if ! git diff --cached --quiet; then
|
||
git commit -m "🦅 天眼报告 · $(date +%Y-%m-%d) · 问题:${{ steps.diagnose.outputs.issues_count }} 自动修复:${{ steps.diagnose.outputs.auto_fixable }}"
|
||
git push
|
||
fi
|
||
|
||
- name: "📡 Phase 7 · 同步到 Notion"
|
||
if: always()
|
||
env:
|
||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
||
NOTION_SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||
SKYEYE_PERSONA_DB_ID: ${{ secrets.SKYEYE_PERSONA_DB_ID }}
|
||
run: |
|
||
node scripts/skyeye/sync-to-notion.js || echo "⚠️ Notion同步失败(不阻断)"
|
||
# 人格体注册表全量同步(双端同步:Notion → 本地配置)
|
||
node scripts/skyeye/persona-lookup.js --sync || echo "⚠️ 人格体注册表同步失败(不阻断)"
|
||
git config user.name "zhuyuan-bot"
|
||
git config user.email "zhuyuan@guanghulab.com"
|
||
git add .github/persona-brain/gate-guard-config.json
|
||
if ! git diff --cached --quiet; then
|
||
git commit -m "🦅 天眼·人格体注册表同步 · $(date +%Y-%m-%d)"
|
||
git push || true
|
||
fi
|
||
|
||
- name: "📧 通知妈妈(仅有严重问题时)"
|
||
if: steps.diagnose.outputs.needs_human != '0'
|
||
env:
|
||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||
SMTP_PASS: ${{ secrets.SMTP_PASS }}
|
||
run: |
|
||
echo "📧 发现 ${{ steps.diagnose.outputs.needs_human }} 个需要妈妈处理的问题"
|
||
echo "工单已记录在天眼报告中 · data/skyeye-reports/"
|
||
# 邮件通知逻辑预留(需要 SMTP 配置完整后启用)
|
||
if [ -n "$SMTP_USER" ] && [ -n "$SMTP_PASS" ]; then
|
||
echo "SMTP 凭证已配置,可发送邮件通知"
|
||
else
|
||
echo "⚠️ SMTP 凭证未配置,跳过邮件通知"
|
||
fi
|