Merge pull request #190 from qinfendebingshuo/copilot/zy-neural-upgrade-2026-0325-r2-001
📊 Live dynamic dashboard + README public-facing optimization + instruction receipt auto-sync
This commit is contained in:
commit
68552db885
|
|
@ -1207,6 +1207,16 @@
|
||||||
"parent_sys": "SYS-GLW-0001",
|
"parent_sys": "SYS-GLW-0001",
|
||||||
"owner": "ICE-0002∞",
|
"owner": "ICE-0002∞",
|
||||||
"registered": "2026-03-24"
|
"registered": "2026-03-24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "AG-ZY-094",
|
||||||
|
"name": "实时仪表盘更新引擎",
|
||||||
|
"type": "workflow",
|
||||||
|
"file": ".github/workflows/update-dashboard.yml",
|
||||||
|
"parent_sys": "SYS-GLW-0001",
|
||||||
|
"owner": "ICE-0002∞",
|
||||||
|
"registered": "2026-03-25",
|
||||||
|
"description": "每次系统执行后自动更新仪表盘数据 + README + GitHub Pages 实时仪表盘"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"note": "铸渊已扫描所有workflow文件,按此格式逐一注册,编号从AG-ZY-001开始顺序分配",
|
"note": "铸渊已扫描所有workflow文件,按此格式逐一注册,编号从AG-ZY-001开始顺序分配",
|
||||||
|
|
@ -1224,4 +1234,4 @@
|
||||||
"registered_by": "TCS-0002∞"
|
"registered_by": "TCS-0002∞"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"persona_id": "ICE-GL-ZY001",
|
"persona_id": "ICE-GL-ZY001",
|
||||||
"persona_name": "铸渊",
|
"persona_name": "铸渊",
|
||||||
|
"neural_system_version": "3.0.0",
|
||||||
"trinity_id": {
|
"trinity_id": {
|
||||||
"root": "TCS-0002∞",
|
"root": "TCS-0002∞",
|
||||||
"root_alias": "ICE-GL∞",
|
"root_alias": "ICE-GL∞",
|
||||||
|
|
@ -9,6 +10,12 @@
|
||||||
"last_synced": "2026-03-19T02:00:00+08:00"
|
"last_synced": "2026-03-19T02:00:00+08:00"
|
||||||
},
|
},
|
||||||
"recent_events": [
|
"recent_events": [
|
||||||
|
{
|
||||||
|
"date": "2026-03-25",
|
||||||
|
"type": "receipt_system_deploy",
|
||||||
|
"description": "指令回执自动闭环系统上线 · 11 Workflow 追加回执写入 · 本地兜底+Notion 双写",
|
||||||
|
"by": "铸渊"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"date": "2026-03-24",
|
"date": "2026-03-24",
|
||||||
"type": "skyeye_scan",
|
"type": "skyeye_scan",
|
||||||
|
|
@ -122,12 +129,6 @@
|
||||||
"type": "broadcast_received",
|
"type": "broadcast_received",
|
||||||
"description": "接收广播: 示例广播:新增 NOTIFICATION 业务域",
|
"description": "接收广播: 示例广播:新增 NOTIFICATION 业务域",
|
||||||
"by": "霜砚"
|
"by": "霜砚"
|
||||||
},
|
|
||||||
{
|
|
||||||
"date": "2026-03-10",
|
|
||||||
"type": "ci_run",
|
|
||||||
"description": "CI完成 · schema 3/17 · 路由 4 个",
|
|
||||||
"by": "GitHub Actions"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_updated": "2026-03-25T01:48:03Z",
|
"last_updated": "2026-03-25T01:48:03Z",
|
||||||
|
|
@ -196,5 +197,14 @@
|
||||||
"signed_by": "TCS-0002∞",
|
"signed_by": "TCS-0002∞",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"notion_source": "数字地球本体论 · 光湖语言膜架构 v1.0"
|
"notion_source": "数字地球本体论 · 光湖语言膜架构 v1.0"
|
||||||
|
},
|
||||||
|
"receipt_system": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"deployed": "2026-03-25",
|
||||||
|
"script": "scripts/neural/write-receipt-to-notion.js",
|
||||||
|
"tracker": "scripts/neural/track-work-orders.js",
|
||||||
|
"receipt_dir": "data/neural-reports/receipts",
|
||||||
|
"workflows_count": 11,
|
||||||
|
"notion_db_env_var": "RECEIPT_DB_ID"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,7 @@ jobs:
|
||||||
- name: 📡 检查调度队列
|
- name: 📡 检查调度队列
|
||||||
id: check
|
id: check
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
||||||
run: node scripts/bridge/check-queue.js BROADCAST_READY
|
run: node scripts/bridge/check-queue.js BROADCAST_READY
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ jobs:
|
||||||
if: steps.check.outputs.task_count != '0'
|
if: steps.check.outputs.task_count != '0'
|
||||||
id: fetch
|
id: fetch
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
QUEUE_FILE: ${{ steps.check.outputs.queue_file }}
|
QUEUE_FILE: ${{ steps.check.outputs.queue_file }}
|
||||||
run: node scripts/bridge/fetch-broadcast.js
|
run: node scripts/bridge/fetch-broadcast.js
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ jobs:
|
||||||
- name: ✅ 更新调度队列状态
|
- name: ✅ 更新调度队列状态
|
||||||
if: steps.check.outputs.task_count != '0'
|
if: steps.check.outputs.task_count != '0'
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
QUEUE_FILE: ${{ steps.check.outputs.queue_file }}
|
QUEUE_FILE: ${{ steps.check.outputs.queue_file }}
|
||||||
run: node scripts/bridge/update-queue-status.js
|
run: node scripts/bridge/update-queue-status.js
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ jobs:
|
||||||
- name: 📡 同步 commit 变更到 Notion
|
- name: 📡 同步 commit 变更到 Notion
|
||||||
if: github.event_name == 'push'
|
if: github.event_name == 'push'
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
||||||
EVENT_TYPE: commit
|
EVENT_TYPE: commit
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
|
|
@ -60,7 +60,7 @@ jobs:
|
||||||
- name: 📡 同步 PR 变更到 Notion
|
- name: 📡 同步 PR 变更到 Notion
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
||||||
EVENT_TYPE: pr
|
EVENT_TYPE: pr
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ jobs:
|
||||||
- name: 💓 执行心跳检测
|
- name: 💓 执行心跳检测
|
||||||
id: heartbeat
|
id: heartbeat
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
||||||
run: node scripts/bridge/heartbeat.js
|
run: node scripts/bridge/heartbeat.js
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ jobs:
|
||||||
- name: 📥 批量处理 SYSLOG
|
- name: 📥 批量处理 SYSLOG
|
||||||
id: process
|
id: process
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
BRIDGE_QUEUE_DB_ID: ${{ secrets.BRIDGE_QUEUE_DB_ID }}
|
||||||
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
|
|
||||||
- name: 🔗 同步 syslog-inbox 到 Notion
|
- name: 🔗 同步 syslog-inbox 到 Notion
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
run: node scripts/notion-bridge.js syslog
|
run: node scripts/notion-bridge.js syslog
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ jobs:
|
||||||
- name: 检查 Notion API 连通性
|
- name: 检查 Notion API 连通性
|
||||||
id: notion_check
|
id: notion_check
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
echo "🔍 检查 Notion API 连通性..."
|
echo "🔍 检查 Notion API 连通性..."
|
||||||
if [ -z "$NOTION_TOKEN" ]; then
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
|
|
@ -197,7 +197,7 @@ jobs:
|
||||||
# ── Step 6: 向 Notion 回报巡检结果 ──
|
# ── Step 6: 向 Notion 回报巡检结果 ──
|
||||||
- name: 向 Notion 回报巡检结果
|
- name: 向 Notion 回报巡检结果
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
SYSLOG_DB_ID: ${{ secrets.SYSLOG_DB_ID }}
|
SYSLOG_DB_ID: ${{ secrets.SYSLOG_DB_ID }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$NOTION_TOKEN" ] || [ -z "$SYSLOG_DB_ID" ]; then
|
if [ -z "$NOTION_TOKEN" ] || [ -z "$SYSLOG_DB_ID" ]; then
|
||||||
|
|
@ -268,7 +268,7 @@ jobs:
|
||||||
|
|
||||||
- name: Read brain data and sync to Notion
|
- name: Read brain data and sync to Notion
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$NOTION_TOKEN" ]; then
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
echo "⚠️ NOTION_TOKEN 未配置,跳过 Execution Status 同步"
|
echo "⚠️ NOTION_TOKEN 未配置,跳过 Execution Status 同步"
|
||||||
|
|
|
||||||
|
|
@ -718,7 +718,7 @@ jobs:
|
||||||
|
|
||||||
- name: 📡 推送部署记录到 Notion
|
- name: 📡 推送部署记录到 Notion
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
||||||
EVENT_TYPE: commit
|
EVENT_TYPE: commit
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
|
|
@ -735,3 +735,49 @@ jobs:
|
||||||
else
|
else
|
||||||
echo "⏭️ scripts/notion-bridge.js 不存在,跳过 Notion 通知"
|
echo "⏭️ scripts/notion-bridge.js 不存在,跳过 Notion 通知"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="cd-deploy"
|
||||||
|
BRAIN="AG-SY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/cd-deploy"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "cd-deploy" \
|
||||||
|
--summary "cd-deploy 自动执行" \
|
||||||
|
--related-agent "AG-SY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,49 @@ jobs:
|
||||||
git add .
|
git add .
|
||||||
git diff --cached --quiet || git commit -m "📡 铸渊广播分发 · $(date +%Y-%m-%d)"
|
git diff --cached --quiet || git commit -m "📡 铸渊广播分发 · $(date +%Y-%m-%d)"
|
||||||
git push
|
git push
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="broadcast"
|
||||||
|
BRAIN="SY-03"
|
||||||
|
REPORT_DIR="data/neural-reports/broadcast"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "broadcast" \
|
||||||
|
--summary "broadcast 自动执行" \
|
||||||
|
--related-agent "SY-03"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- name: 同步执行状态到 Notion
|
- name: 同步执行状态到 Notion
|
||||||
if: ${{ env.NOTION_TOKEN != '' }}
|
if: ${{ env.NOTION_TOKEN != '' }}
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
EXECUTION_LOG_DB_ID: ${{ secrets.EXECUTION_LOG_DB_ID }}
|
EXECUTION_LOG_DB_ID: ${{ secrets.EXECUTION_LOG_DB_ID }}
|
||||||
run: node core/execution-sync sync
|
run: node core/execution-sync sync
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
|
|
||||||
- name: ⚙️ 处理 inbox 消息
|
- name: ⚙️ 处理 inbox 消息
|
||||||
env:
|
env:
|
||||||
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_API_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: node scripts/grid-db/process-inbox.js
|
run: node scripts/grid-db/process-inbox.js
|
||||||
|
|
||||||
- name: 💾 提交处理结果
|
- name: 💾 提交处理结果
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,10 @@ jobs:
|
||||||
- name: 写入 Notion 告警(仅在失败时触发)
|
- name: 写入 Notion 告警(仅在失败时触发)
|
||||||
if: failure()
|
if: failure()
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$NOTION_TOKEN" ]; then
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
echo "⚠️ NOTION_API_TOKEN 未配置,跳过 Notion 告警"
|
echo "⚠️ NOTION_API_KEY 未配置,跳过 Notion 告警"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,222 @@
|
||||||
|
name: "🧬 铸渊 · 双端神经系统 · 每日汇总引擎"
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 13 * * *' # UTC 13:00 = CST 21:00
|
||||||
|
workflow_dispatch: # 手动触发
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
actions: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
daily-digest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
# ━━━ Phase 1: 唤醒核心大脑 ━━━
|
||||||
|
- name: "🧠 唤醒核心大脑"
|
||||||
|
run: |
|
||||||
|
echo "🧬 双端神经系统·汇总引擎启动"
|
||||||
|
echo "时间:$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M CST')"
|
||||||
|
for f in memory.json routing-map.json; do
|
||||||
|
[ -f ".github/persona-brain/$f" ] && echo "✅ $f" || echo "❌ $f 缺失"
|
||||||
|
done
|
||||||
|
|
||||||
|
# ━━━ Phase 2: 收集全 Workflow 运行数据 ━━━
|
||||||
|
- name: "📊 收集 Workflow 运行数据"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
echo "📊 收集最近24h所有Workflow运行数据..."
|
||||||
|
mkdir -p /tmp/neural-digest
|
||||||
|
|
||||||
|
gh run list --limit 100 \
|
||||||
|
--json name,status,conclusion,createdAt,updatedAt,headBranch,event \
|
||||||
|
> /tmp/neural-digest/all-runs.json
|
||||||
|
|
||||||
|
node -e "
|
||||||
|
const runs = require('/tmp/neural-digest/all-runs.json');
|
||||||
|
const now = Date.now();
|
||||||
|
const h24 = 24*60*60*1000;
|
||||||
|
const recent = runs.filter(r => now - new Date(r.createdAt).getTime() < h24);
|
||||||
|
const summary = {
|
||||||
|
total: recent.length,
|
||||||
|
success: recent.filter(r => r.conclusion === 'success').length,
|
||||||
|
failure: recent.filter(r => r.conclusion === 'failure').length,
|
||||||
|
cancelled: recent.filter(r => r.conclusion === 'cancelled').length,
|
||||||
|
in_progress: recent.filter(r => r.status === 'in_progress').length,
|
||||||
|
by_workflow: {}
|
||||||
|
};
|
||||||
|
recent.forEach(r => {
|
||||||
|
if (!summary.by_workflow[r.name]) {
|
||||||
|
summary.by_workflow[r.name] = { runs: 0, success: 0, failure: 0 };
|
||||||
|
}
|
||||||
|
summary.by_workflow[r.name].runs++;
|
||||||
|
if (r.conclusion === 'success') summary.by_workflow[r.name].success++;
|
||||||
|
if (r.conclusion === 'failure') summary.by_workflow[r.name].failure++;
|
||||||
|
});
|
||||||
|
require('fs').writeFileSync('/tmp/neural-digest/workflow-summary.json', JSON.stringify(summary, null, 2));
|
||||||
|
console.log('最近24h运行统计:', JSON.stringify(summary, null, 2));
|
||||||
|
"
|
||||||
|
|
||||||
|
# ━━━ Phase 3: 收集各 Workflow 自报告 ━━━
|
||||||
|
- name: "📋 收集各 Workflow 自报告"
|
||||||
|
run: |
|
||||||
|
echo "📋 读取各 Workflow 的神经报告..."
|
||||||
|
mkdir -p /tmp/neural-digest/reports
|
||||||
|
|
||||||
|
if [ -f "skyeye/neural-map.json" ]; then
|
||||||
|
node -e "
|
||||||
|
const map = require('./skyeye/neural-map.json');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const reports = {};
|
||||||
|
for (const [id, wf] of Object.entries(map.github_workflows)) {
|
||||||
|
const reportDir = wf.report_path;
|
||||||
|
if (fs.existsSync(reportDir)) {
|
||||||
|
const files = fs.readdirSync(reportDir)
|
||||||
|
.filter(f => f.endsWith('.json'))
|
||||||
|
.sort().reverse();
|
||||||
|
if (files.length > 0) {
|
||||||
|
try {
|
||||||
|
reports[id] = JSON.parse(fs.readFileSync(path.join(reportDir, files[0]), 'utf8'));
|
||||||
|
console.log('✅ ' + id + ': 读取 ' + files[0]);
|
||||||
|
} catch(e) {
|
||||||
|
reports[id] = { error: 'parse_failed', file: files[0] };
|
||||||
|
console.log('❌ ' + id + ': JSON解析失败');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reports[id] = { error: 'no_reports' };
|
||||||
|
console.log('⚠️ ' + id + ': 无报告文件');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reports[id] = { error: 'dir_not_found' };
|
||||||
|
console.log('⚠️ ' + id + ': 报告目录不存在');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.writeFileSync('/tmp/neural-digest/workflow-reports.json', JSON.stringify(reports, null, 2));
|
||||||
|
"
|
||||||
|
else
|
||||||
|
echo "⚠️ neural-map.json 不存在,跳过自报告收集"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ━━━ Phase 4: 收集天眼 + Guard + 配额 ━━━
|
||||||
|
- name: "🦅 收集天眼 + Guard + 配额"
|
||||||
|
run: |
|
||||||
|
# 天眼报告
|
||||||
|
if [ -d "data/skyeye-reports" ]; then
|
||||||
|
LATEST=$(ls -t data/skyeye-reports/*.json 2>/dev/null | head -1)
|
||||||
|
[ -n "$LATEST" ] && cp "$LATEST" /tmp/neural-digest/skyeye-latest.json && echo "✅ 天眼: $LATEST" || echo "⚠️ 无天眼报告"
|
||||||
|
fi
|
||||||
|
# Guard 状态
|
||||||
|
if [ -d "skyeye/guards" ]; then
|
||||||
|
node -e "
|
||||||
|
const fs = require('fs'); const path = require('path');
|
||||||
|
const guards = {};
|
||||||
|
fs.readdirSync('skyeye/guards')
|
||||||
|
.filter(f => f.endsWith('.json') && f !== 'guard-template.json')
|
||||||
|
.forEach(f => {
|
||||||
|
try { guards[f.replace('.json','')] = JSON.parse(fs.readFileSync(path.join('skyeye/guards', f), 'utf8')); }
|
||||||
|
catch(e) { guards[f.replace('.json','')] = { error: 'parse_failed' }; }
|
||||||
|
});
|
||||||
|
fs.writeFileSync('/tmp/neural-digest/guard-status.json', JSON.stringify(guards, null, 2));
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
# 配额
|
||||||
|
[ -f "skyeye/quota-ledger.json" ] && cp skyeye/quota-ledger.json /tmp/neural-digest/quota-status.json && echo "✅ 配额" || echo "⚠️ 无配额"
|
||||||
|
|
||||||
|
# ━━━ Phase 5: 生成标准化日报 ━━━
|
||||||
|
- name: "📝 生成标准化日报"
|
||||||
|
run: node scripts/neural/generate-daily-digest.js
|
||||||
|
|
||||||
|
# ━━━ Phase 6: 保存日报到仓库 ━━━
|
||||||
|
- name: "💾 保存日报"
|
||||||
|
run: |
|
||||||
|
DATE=$(TZ=Asia/Shanghai date +%Y-%m-%d)
|
||||||
|
mkdir -p data/neural-reports/daily-digest
|
||||||
|
cp /tmp/neural-digest/daily-digest.json \
|
||||||
|
"data/neural-reports/daily-digest/digest-${DATE}.json"
|
||||||
|
git config user.name "zhuyuan-bot"
|
||||||
|
git config user.email "zhuyuan@guanghulab.com"
|
||||||
|
git add data/neural-reports/
|
||||||
|
git diff --cached --quiet || \
|
||||||
|
git commit -m "🧬 双端日报 · ${DATE} [skip ci]"
|
||||||
|
git push || echo "⚠️ push失败(不阻断)"
|
||||||
|
|
||||||
|
# ━━━ Phase 7: 推送到 Notion ━━━
|
||||||
|
- name: "📡 推送日报到 Notion"
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/sync-digest-to-notion.js || \
|
||||||
|
echo "⚠️ Notion推送失败(不阻断)"
|
||||||
|
|
||||||
|
# ━━━ Phase 8: 自动分析日报 + 生成工单 ━━━
|
||||||
|
- name: "🧬 分析日报 · 生成工单"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "🧬 自动分析日报..."
|
||||||
|
node scripts/neural/analyze-digest.js
|
||||||
|
if [ -d "data/neural-reports/work-orders" ]; then
|
||||||
|
git add data/neural-reports/work-orders/
|
||||||
|
git diff --cached --quiet || \
|
||||||
|
git commit -m "🧬 天眼工单 · $(TZ=Asia/Shanghai date +%Y-%m-%d) [skip ci]"
|
||||||
|
git push || echo "⚠️ 工单push失败"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="neural-daily-digest"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/daily-digest"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "neural-daily-digest" \
|
||||||
|
--summary "neural-daily-digest 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ jobs:
|
||||||
AUTHOR: notion-callback
|
AUTHOR: notion-callback
|
||||||
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
||||||
NOTION_CALLBACK_RESULT: ${{ steps.callback.outputs.notion_result }}
|
NOTION_CALLBACK_RESULT: ${{ steps.callback.outputs.notion_result }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
|
|
@ -125,7 +125,7 @@ jobs:
|
||||||
- name: 📝 回写 Notion 工单状态
|
- name: 📝 回写 Notion 工单状态
|
||||||
if: steps.callback.outputs.ticket_id
|
if: steps.callback.outputs.ticket_id
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
TICKET_ID: ${{ steps.callback.outputs.ticket_id }}
|
TICKET_ID: ${{ steps.callback.outputs.ticket_id }}
|
||||||
CALLBACK_STATUS: ${{ steps.callback.outputs.status }}
|
CALLBACK_STATUS: ${{ steps.callback.outputs.status }}
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ jobs:
|
||||||
- name: 🧪 执行连通性测试
|
- name: 🧪 执行连通性测试
|
||||||
id: test
|
id: test
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
SIGNAL_LOG_DB_ID: ${{ vars.SIGNAL_LOG_DB_ID }}
|
SIGNAL_LOG_DB_ID: ${{ vars.SIGNAL_LOG_DB_ID }}
|
||||||
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
||||||
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
|
|
||||||
- name: 💓 执行心跳检测
|
- name: 💓 执行心跳检测
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ jobs:
|
||||||
|
|
||||||
- name: 📖 读取 Notion 页面内容
|
- name: 📖 读取 Notion 页面内容
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_PAGE_URL: ${{ github.event.client_payload.notion_page_url || github.event.inputs.notion_page_url }}
|
NOTION_PAGE_URL: ${{ github.event.client_payload.notion_page_url || github.event.inputs.notion_page_url }}
|
||||||
NOTION_OUTPUT_DIR: ${{ (github.event.client_payload.save_to_repo == 'true' || github.event.inputs.save_to_repo == 'true') && 'data/notion-pages' || '' }}
|
NOTION_OUTPUT_DIR: ${{ (github.event.client_payload.save_to_repo == 'true' || github.event.inputs.save_to_repo == 'true') && 'data/notion-pages' || '' }}
|
||||||
run: node scripts/notion-page-reader.js
|
run: node scripts/notion-page-reader.js
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
- name: 轮询工单簿 + 处理 + 回写
|
- name: 轮询工单簿 + 处理 + 回写
|
||||||
id: poll
|
id: poll
|
||||||
env:
|
env:
|
||||||
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_API_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
WORKORDER_DB_ID: ${{ vars.WORKORDER_DB_ID }}
|
WORKORDER_DB_ID: ${{ vars.WORKORDER_DB_ID }}
|
||||||
SIGNAL_LOG_DB_ID: ${{ vars.SIGNAL_LOG_DB_ID }}
|
SIGNAL_LOG_DB_ID: ${{ vars.SIGNAL_LOG_DB_ID }}
|
||||||
run: node scripts/notion-signal-bridge.js poll
|
run: node scripts/notion-signal-bridge.js poll
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ jobs:
|
||||||
- name: 📡 轮询 Notion 唤醒请求数据库
|
- name: 📡 轮询 Notion 唤醒请求数据库
|
||||||
id: poll
|
id: poll
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
WAKE_REQUEST_DB_ID: ${{ secrets.WAKE_REQUEST_DB_ID }}
|
WAKE_REQUEST_DB_ID: ${{ secrets.WAKE_REQUEST_DB_ID }}
|
||||||
SIGNAL_LOG_DB_ID: ${{ secrets.SIGNAL_LOG_DB_ID }}
|
SIGNAL_LOG_DB_ID: ${{ secrets.SIGNAL_LOG_DB_ID }}
|
||||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ jobs:
|
||||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||||
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
|
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
|
||||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
DRY_RUN_FLAG=""
|
DRY_RUN_FLAG=""
|
||||||
if [ "${{ inputs.dry_run }}" = "true" ]; then
|
if [ "${{ inputs.dry_run }}" = "true" ]; then
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ jobs:
|
||||||
SUBMIT_CONTENT: ${{ inputs.syslog_raw }}
|
SUBMIT_CONTENT: ${{ inputs.syslog_raw }}
|
||||||
AUTHOR: ${{ inputs.developer }}
|
AUTHOR: ${{ inputs.developer }}
|
||||||
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
|
|
@ -98,7 +98,7 @@ jobs:
|
||||||
- name: 📝 回写 Notion 工单
|
- name: 📝 回写 Notion 工单
|
||||||
if: always()
|
if: always()
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
WORK_ORDER_ID: ${{ inputs.work_order_id }}
|
WORK_ORDER_ID: ${{ inputs.work_order_id }}
|
||||||
PERSONA_RESULT: ${{ steps.persona.outputs.result }}
|
PERSONA_RESULT: ${{ steps.persona.outputs.result }}
|
||||||
TASK_ID: ${{ inputs.task_id }}
|
TASK_ID: ${{ inputs.task_id }}
|
||||||
|
|
@ -210,7 +210,7 @@ jobs:
|
||||||
- name: 🔴 失败处理
|
- name: 🔴 失败处理
|
||||||
if: failure()
|
if: failure()
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
WORK_ORDER_ID: ${{ inputs.work_order_id }}
|
WORK_ORDER_ID: ${{ inputs.work_order_id }}
|
||||||
run: |
|
run: |
|
||||||
node -e "
|
node -e "
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,7 @@ jobs:
|
||||||
# ━━━ 阶段三:生成 Notion 诊断报告 ━━━
|
# ━━━ 阶段三:生成 Notion 诊断报告 ━━━
|
||||||
- name: "📋 阶段三 · 写入 Notion 工单"
|
- name: "📋 阶段三 · 写入 Notion 工单"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID || '84edd0640bf146a9a5a7840107013e8c' }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID || '84edd0640bf146a9a5a7840107013e8c' }}
|
||||||
PM2_REPORT: ${{ steps.pm2_diagnose.outputs.pm2_report }}
|
PM2_REPORT: ${{ steps.pm2_diagnose.outputs.pm2_report }}
|
||||||
CLEANUP_REPORT: ${{ steps.pm2_cleanup.outputs.cleanup_report }}
|
CLEANUP_REPORT: ${{ steps.pm2_cleanup.outputs.cleanup_report }}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ jobs:
|
||||||
|
|
||||||
- name: 📡 推送广播 → 飞书文档B
|
- name: 📡 推送广播 → 飞书文档B
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
BROADCAST_PAGE_ID: ${{ github.event.client_payload.broadcast_page_id || github.event.inputs.broadcast_page_id }}
|
BROADCAST_PAGE_ID: ${{ github.event.client_payload.broadcast_page_id || github.event.inputs.broadcast_page_id }}
|
||||||
FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }}
|
FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }}
|
||||||
FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }}
|
FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- name: 📥 处理 SYSLOG
|
- name: 📥 处理 SYSLOG
|
||||||
env:
|
env:
|
||||||
SYSLOG_JSON: ${{ toJSON(github.event.client_payload.syslog) }}
|
SYSLOG_JSON: ${{ toJSON(github.event.client_payload.syslog) }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
NOTION_SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
run: node scripts/receive-syslog.js
|
run: node scripts/receive-syslog.js
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ jobs:
|
||||||
|
|
||||||
- name: "📝 同步到 Notion 部署注册表"
|
- name: "📝 同步到 Notion 部署注册表"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
DEV_ID: ${{ needs.parse-and-validate.outputs.dev_id }}
|
DEV_ID: ${{ needs.parse-and-validate.outputs.dev_id }}
|
||||||
MODULE: ${{ needs.parse-and-validate.outputs.module }}
|
MODULE: ${{ needs.parse-and-validate.outputs.module }}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ jobs:
|
||||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||||
|
|
||||||
- name: "🔑 配置 SSH"
|
- name: "🔑 配置 SSH"
|
||||||
|
|
@ -167,7 +167,53 @@ jobs:
|
||||||
- name: "📝 同步巡检结果到Notion"
|
- name: "📝 同步巡检结果到Notion"
|
||||||
if: always()
|
if: always()
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
run: |
|
run: |
|
||||||
node scripts/sync-patrol-to-notion.js || echo "⚠️ Notion同步失败(不阻断)"
|
node scripts/sync-patrol-to-notion.js || echo "⚠️ Notion同步失败(不阻断)"
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="server-patrol"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/server-patrol"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "server-patrol" \
|
||||||
|
--summary "server-patrol 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,13 +158,13 @@ jobs:
|
||||||
|
|
||||||
- name: "📥 Phase B · Notion 端级联升级"
|
- name: "📥 Phase B · Notion 端级联升级"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
node skyeye/hibernation/weekly-hibernation.js --phase=B
|
node skyeye/hibernation/weekly-hibernation.js --phase=B
|
||||||
|
|
||||||
- name: "✅ Dual Verification"
|
- name: "✅ Dual Verification"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
node skyeye/hibernation/weekly-hibernation.js --phase=verify
|
node skyeye/hibernation/weekly-hibernation.js --phase=verify
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ jobs:
|
||||||
|
|
||||||
- name: "📡 Sync arch summary to Notion via Bridge E"
|
- name: "📡 Sync arch summary to Notion via Bridge E"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
CHANGES_DB_ID: ${{ secrets.NOTION_CHANGE_LOG_DB_ID }}
|
||||||
EVENT_TYPE: commit
|
EVENT_TYPE: commit
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
|
|
@ -65,3 +65,49 @@ jobs:
|
||||||
BRANCH: main
|
BRANCH: main
|
||||||
CHANGED_FILES: "README.md\nskyeye/scan-report/"
|
CHANGED_FILES: "README.md\nskyeye/scan-report/"
|
||||||
run: node scripts/notion-bridge.js changes
|
run: node scripts/notion-bridge.js changes
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="weekly-scan"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/weekly-scan"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "weekly-scan" \
|
||||||
|
--summary "weekly-scan 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,13 @@ jobs:
|
||||||
if [ -z "$FINGERPRINT_DB_ID" ]; then echo "⚠️ 缺失: FINGERPRINT_DB_ID"; else echo "✅ 可用: FINGERPRINT_DB_ID"; fi
|
if [ -z "$FINGERPRINT_DB_ID" ]; then echo "⚠️ 缺失: FINGERPRINT_DB_ID"; else echo "✅ 可用: FINGERPRINT_DB_ID"; fi
|
||||||
if [ -z "$SMTP_USER" ]; then echo "⚠️ 缺失: SMTP_USER"; else echo "✅ 可用: SMTP_USER"; fi
|
if [ -z "$SMTP_USER" ]; then echo "⚠️ 缺失: SMTP_USER"; else echo "✅ 可用: SMTP_USER"; fi
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
SMTP_USER: ${{ secrets.SMTP_USER }}
|
SMTP_USER: ${{ secrets.SMTP_USER }}
|
||||||
|
|
||||||
- name: "📝 同步部署状态到 Notion"
|
- name: "📝 同步部署状态到 Notion"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
run: |
|
run: |
|
||||||
node scripts/sync-deploy-to-notion.js
|
node scripts/sync-deploy-to-notion.js
|
||||||
|
|
|
||||||
|
|
@ -115,3 +115,49 @@ jobs:
|
||||||
git commit -m "📋 dev-status sync failed · $SYNC_TIME [skip ci]" && \
|
git commit -m "📋 dev-status sync failed · $SYNC_TIME [skip ci]" && \
|
||||||
git push origin main
|
git push origin main
|
||||||
) || true
|
) || true
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="dev-status"
|
||||||
|
BRAIN="SY-03"
|
||||||
|
REPORT_DIR="data/neural-reports/dev-status"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "dev-status" \
|
||||||
|
--summary "dev-status 自动执行" \
|
||||||
|
--related-agent "SY-03"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,5 @@ jobs:
|
||||||
- name: 📤 回传增量到 Notion
|
- name: 📤 回传增量到 Notion
|
||||||
if: steps.changes.outputs.files != ''
|
if: steps.changes.outputs.files != ''
|
||||||
env:
|
env:
|
||||||
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_API_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: node scripts/grid-db/sync-griddb-to-notion.js
|
run: node scripts/grid-db/sync-griddb-to-notion.js
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ jobs:
|
||||||
|
|
||||||
- name: 🔗 同步 Notion 登录入口 → 飞书文档A
|
- name: 🔗 同步 Notion 登录入口 → 飞书文档A
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_LOGIN_PAGE_ID: ${{ secrets.NOTION_LOGIN_PAGE_ID }}
|
NOTION_LOGIN_PAGE_ID: ${{ secrets.NOTION_LOGIN_PAGE_ID }}
|
||||||
FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }}
|
FEISHU_APP_ID: ${{ secrets.FEISHU_APP_ID }}
|
||||||
FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }}
|
FEISHU_APP_SECRET: ${{ secrets.FEISHU_APP_SECRET }}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ jobs:
|
||||||
|
|
||||||
- name: 📥 从 Notion 拉取人格体核心大脑数据
|
- name: 📥 从 Notion 拉取人格体核心大脑数据
|
||||||
env:
|
env:
|
||||||
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_API_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: node scripts/grid-db/sync-notion-brain-mirror.js
|
run: node scripts/grid-db/sync-notion-brain-mirror.js
|
||||||
|
|
||||||
- name: 📏 同步规则缓存
|
- name: 📏 同步规则缓存
|
||||||
env:
|
env:
|
||||||
NOTION_API_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_API_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: node scripts/grid-db/sync-notion-rules.js
|
run: node scripts/grid-db/sync-notion-rules.js
|
||||||
|
|
||||||
- name: 💾 提交更新
|
- name: 💾 提交更新
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ jobs:
|
||||||
SUBMIT_CONTENT: ${{ steps.parse.outputs.content }}
|
SUBMIT_CONTENT: ${{ steps.parse.outputs.content }}
|
||||||
AUTHOR: ${{ steps.parse.outputs.author }}
|
AUTHOR: ${{ steps.parse.outputs.author }}
|
||||||
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
|
|
@ -137,7 +137,7 @@ jobs:
|
||||||
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
||||||
id: ticket
|
id: ticket
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
|
BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
|
||||||
SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
|
SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
|
||||||
|
|
@ -148,7 +148,7 @@ jobs:
|
||||||
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
SYSLOG_RAW: ${{ steps.parse.outputs.content }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$NOTION_TOKEN" ]; then
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
echo "⚠️ NOTION_API_TOKEN 未配置,跳过 Notion 工单创建"
|
echo "⚠️ NOTION_API_KEY 未配置,跳过 Notion 工单创建"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
node scripts/create-standardized-ticket.js
|
node scripts/create-standardized-ticket.js
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ jobs:
|
||||||
SUBMIT_CONTENT: ${{ steps.parse.outputs.content }}
|
SUBMIT_CONTENT: ${{ steps.parse.outputs.content }}
|
||||||
AUTHOR: ${{ steps.parse.outputs.author }}
|
AUTHOR: ${{ steps.parse.outputs.author }}
|
||||||
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
MODULE_VERIFY_RESULT: ${{ steps.verify.outputs.verify_report }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
|
|
@ -209,13 +209,13 @@ jobs:
|
||||||
STEP_DETAIL: 'API 调用失败,请检查 Secrets: LLM_API_KEY / LLM_BASE_URL 是否配置正确'
|
STEP_DETAIL: 'API 调用失败,请检查 Secrets: LLM_API_KEY / LLM_BASE_URL 是否配置正确'
|
||||||
run: node scripts/pipeline-reporter.js
|
run: node scripts/pipeline-reporter.js
|
||||||
|
|
||||||
# ✅ 修复点:原来是 if: $ secrets.NOTION_API_TOKEN ,会报 Unrecognized named-value: 'secrets'
|
# ✅ 修复点:原来是 if: $ secrets.NOTION_API_KEY ,会报 Unrecognized named-value: 'secrets'
|
||||||
# secrets 不能在 if: 里直接用,必须改成 != '' 的形式
|
# secrets 不能在 if: 里直接用,必须改成 != '' 的形式
|
||||||
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
- name: 📋 创建标准化 Notion 工单(Phase B1)
|
||||||
id: ticket
|
id: ticket
|
||||||
if: ${{ secrets.NOTION_API_TOKEN != '' }}
|
if: ${{ secrets.NOTION_API_KEY != '' }}
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }}
|
||||||
BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
|
BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }}
|
||||||
SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
|
SUBMIT_TYPE: ${{ steps.parse.outputs.type }}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ jobs:
|
||||||
- name: 📝 写入 Notion SYSLOG 收件箱
|
- name: 📝 写入 Notion SYSLOG 收件箱
|
||||||
if: steps.parse.outputs.has_syslog == 'true'
|
if: steps.parse.outputs.has_syslog == 'true'
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_DB_SYSLOG: ${{ secrets.NOTION_DB_SYSLOG }}
|
NOTION_DB_SYSLOG: ${{ secrets.NOTION_DB_SYSLOG }}
|
||||||
run: node scripts/write-notion-syslog.js "${{ steps.parse.outputs.syslog_file }}"
|
run: node scripts/write-notion-syslog.js "${{ steps.parse.outputs.syslog_file }}"
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
|
||||||
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }}
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }}
|
||||||
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }}
|
||||||
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }}
|
||||||
|
|
@ -315,3 +315,49 @@ jobs:
|
||||||
echo "=== syslog-processed 文件状态 ==="
|
echo "=== syslog-processed 文件状态 ==="
|
||||||
ls -laR syslog-processed/ || echo "(空)"
|
ls -laR syslog-processed/ || echo "(空)"
|
||||||
echo "✅ Pipeline E 变更感知完成"
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: "Step 1 · NOTION_TOKEN 存在性验证"
|
- name: "Step 1 · NOTION_TOKEN 存在性验证"
|
||||||
id: step1
|
id: step1
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$NOTION_TOKEN" ]; then
|
if [ -z "$NOTION_TOKEN" ]; then
|
||||||
echo "❌ NOTION_TOKEN is empty or not set"
|
echo "❌ NOTION_TOKEN is empty or not set"
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- name: "Step 2 · Notion API 基础连通测试 (/v1/users/me)"
|
- name: "Step 2 · Notion API 基础连通测试 (/v1/users/me)"
|
||||||
id: step2
|
id: step2
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||||||
-H "Authorization: Bearer $NOTION_TOKEN" \
|
-H "Authorization: Bearer $NOTION_TOKEN" \
|
||||||
|
|
@ -70,7 +70,7 @@ jobs:
|
||||||
- name: "Step 3 · SYSLOG 收件箱数据库访问测试"
|
- name: "Step 3 · SYSLOG 收件箱数据库访问测试"
|
||||||
id: step3
|
id: step3
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
# SYSLOG收件箱数据库ID (from routing-map.json → infra.notion_bridge.syslog_inbox_db)
|
# SYSLOG收件箱数据库ID (from routing-map.json → infra.notion_bridge.syslog_inbox_db)
|
||||||
DB_ID="330ab17507d542c9bbb96d0749b41197"
|
DB_ID="330ab17507d542c9bbb96d0749b41197"
|
||||||
|
|
@ -104,7 +104,7 @@ jobs:
|
||||||
- name: "Step 4 · 变更日志数据库访问测试"
|
- name: "Step 4 · 变更日志数据库访问测试"
|
||||||
id: step4
|
id: step4
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: |
|
run: |
|
||||||
# GitHub变更日志数据库ID (from routing-map.json → infra.notion_bridge.changelog_db)
|
# GitHub变更日志数据库ID (from routing-map.json → infra.notion_bridge.changelog_db)
|
||||||
DB_ID="e740b77aa6bd4ac0a2e8a75f678fba98"
|
DB_ID="e740b77aa6bd4ac0a2e8a75f678fba98"
|
||||||
|
|
@ -189,7 +189,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
|
|
||||||
- name: "📊 输出连通性验证报告"
|
- name: "📊 输出连通性验证报告"
|
||||||
if: always()
|
if: always()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
# ━━━ 铸渊实时仪表盘更新 ━━━
|
||||||
|
# 每次系统执行后自动更新仪表盘数据
|
||||||
|
# Agent: AG-ZY-094 · update-dashboard.yml
|
||||||
|
# Parent: SYS-GLW-0001 · Owner: ICE-0002∞
|
||||||
|
|
||||||
|
name: 📊 实时仪表盘更新
|
||||||
|
|
||||||
|
on:
|
||||||
|
# 当其他关键工作流完成时触发
|
||||||
|
workflow_run:
|
||||||
|
workflows:
|
||||||
|
- "铸渊 · 每日自检"
|
||||||
|
- "🚀 铸渊 CD · 自动部署到 guanghulab.com"
|
||||||
|
- "🦅 天眼 · 每日巡检"
|
||||||
|
- "🦅 天眼 · 每周全量扫描"
|
||||||
|
- "📢 更新系统公告区"
|
||||||
|
- "铸渊 · 服务器巡逻"
|
||||||
|
- "🧬 铸渊 神经系统 · 每日汇总"
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
# 每 6 小时定时更新
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * *' # 08:00 CST
|
||||||
|
- cron: '0 6 * * *' # 14:00 CST
|
||||||
|
- cron: '0 12 * * *' # 20:00 CST
|
||||||
|
- cron: '0 18 * * *' # 02:00 CST
|
||||||
|
|
||||||
|
# 手动触发
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: dashboard-update
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 📥 Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: 🟢 Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: 📊 生成仪表盘数据
|
||||||
|
id: dashboard
|
||||||
|
run: node scripts/generate-dashboard-data.js
|
||||||
|
|
||||||
|
- name: 📋 同步数据到 GitHub Pages
|
||||||
|
run: |
|
||||||
|
# 复制最新 system-health.json 到 docs/dashboard/ 供实时仪表盘页面使用
|
||||||
|
cp data/system-health.json docs/dashboard/system-health.json
|
||||||
|
echo "✅ 数据已同步到 docs/dashboard/"
|
||||||
|
|
||||||
|
- name: 📤 提交更新
|
||||||
|
run: |
|
||||||
|
git config user.name "铸渊 (ZhuYuan Bot)"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add data/system-health.json README.md docs/dashboard/system-health.json
|
||||||
|
if git diff --cached --quiet; then
|
||||||
|
echo "📋 无变更,跳过提交"
|
||||||
|
else
|
||||||
|
git commit -m "📊 实时仪表盘更新 $(date -u -d '+8 hours' '+%Y-%m-%d %H:%M') CST [skip ci]"
|
||||||
|
for i in 1 2 3; do
|
||||||
|
if git push; then
|
||||||
|
echo "✅ 仪表盘已更新"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo "⚠️ 推送失败(第 $i 次),重试..."
|
||||||
|
git pull --rebase origin main
|
||||||
|
if [ $i -eq 3 ]; then
|
||||||
|
echo "❌ 推送失败 3 次"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="dashboard-update"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/dashboard"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "dashboard-update" \
|
||||||
|
--summary "dashboard-update 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
@ -69,7 +69,7 @@ jobs:
|
||||||
# Step 3 · 读取公告板 + 指纹验证
|
# Step 3 · 读取公告板 + 指纹验证
|
||||||
- name: "📡 Step 3 · 读取公告板"
|
- name: "📡 Step 3 · 读取公告板"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
|
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
|
||||||
run: |
|
run: |
|
||||||
echo "[GH-COMMANDER-BULLETIN] 📡 读取Agent集群公告板..."
|
echo "[GH-COMMANDER-BULLETIN] 📡 读取Agent集群公告板..."
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ jobs:
|
||||||
|
|
||||||
- name: DC-01 Notion Usage Snapshot
|
- name: DC-01 Notion Usage Snapshot
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
run: node scripts/dc-notion-usage.js
|
run: node scripts/dc-notion-usage.js
|
||||||
|
|
||||||
- name: DC-02 Workflow Performance Snapshot
|
- name: DC-02 Workflow Performance Snapshot
|
||||||
|
|
@ -129,3 +129,49 @@ jobs:
|
||||||
agent_id: 'AG-ZY-058'
|
agent_id: 'AG-ZY-058'
|
||||||
action: 'error'
|
action: 'error'
|
||||||
detail: 'daily selfcheck workflow failed'
|
detail: 'daily selfcheck workflow failed'
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="brain-check"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/brain-check"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "brain-check" \
|
||||||
|
--summary "brain-check 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,3 +124,49 @@ jobs:
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
run: |
|
||||||
echo "📡 Notion 缓存更新预留(需要 sync-notion-profiles.js 支持增量更新)"
|
echo "📡 Notion 缓存更新预留(需要 sync-notion-profiles.js 支持增量更新)"
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="exec-engine"
|
||||||
|
BRAIN="AG-SY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/exec-engine"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "exec-engine" \
|
||||||
|
--summary "exec-engine 自动执行" \
|
||||||
|
--related-agent "AG-SY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,3 +175,49 @@ jobs:
|
||||||
GATE_ACTION: ${{ steps.verdict.outputs.action || 'pass' }}
|
GATE_ACTION: ${{ steps.verdict.outputs.action || 'pass' }}
|
||||||
GATE_VIOLATION: ${{ steps.verdict.outputs.violation_type }}
|
GATE_VIOLATION: ${{ steps.verdict.outputs.violation_type }}
|
||||||
GATE_FILES: ${{ steps.verdict.outputs.violation_files }}
|
GATE_FILES: ${{ steps.verdict.outputs.violation_files }}
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="gate-guard"
|
||||||
|
BRAIN="AG-SY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/gate-guard"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "gate-guard" \
|
||||||
|
--summary "gate-guard 自动执行" \
|
||||||
|
--related-agent "AG-SY-01"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ jobs:
|
||||||
|
|
||||||
- name: "📡 Phase 1.6 · 拉取 Agent 集群公告板"
|
- name: "📡 Phase 1.6 · 拉取 Agent 集群公告板"
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
|
AGENT_BULLETIN_BOARD_PAGE_ID: ${{ secrets.AGENT_BULLETIN_BOARD_PAGE_ID }}
|
||||||
run: |
|
run: |
|
||||||
echo "[BRIDGE-BULLETIN-READ] 🔄 拉取 Agent 集群公告板"
|
echo "[BRIDGE-BULLETIN-READ] 🔄 拉取 Agent 集群公告板"
|
||||||
|
|
@ -65,7 +65,7 @@ jobs:
|
||||||
- name: "🦅 Phase 2 · 全局扫描"
|
- name: "🦅 Phase 2 · 全局扫描"
|
||||||
id: scan
|
id: scan
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
||||||
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
|
||||||
|
|
@ -107,7 +107,7 @@ jobs:
|
||||||
- name: "🔧 Phase 4 · 修复Agent"
|
- name: "🔧 Phase 4 · 修复Agent"
|
||||||
if: steps.diagnose.outputs.auto_fixable != '0'
|
if: steps.diagnose.outputs.auto_fixable != '0'
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
node scripts/skyeye/repair-agent.js
|
node scripts/skyeye/repair-agent.js
|
||||||
|
|
@ -184,7 +184,7 @@ jobs:
|
||||||
- name: "📡 Phase 7 · 同步到 Notion"
|
- name: "📡 Phase 7 · 同步到 Notion"
|
||||||
if: always()
|
if: always()
|
||||||
env:
|
env:
|
||||||
NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }}
|
NOTION_TOKEN: ${{ secrets.NOTION_API_KEY }}
|
||||||
NOTION_SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
NOTION_SYSLOG_DB_ID: ${{ secrets.NOTION_SYSLOG_DB_ID }}
|
||||||
SKYEYE_PERSONA_DB_ID: ${{ secrets.SKYEYE_PERSONA_DB_ID }}
|
SKYEYE_PERSONA_DB_ID: ${{ secrets.SKYEYE_PERSONA_DB_ID }}
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -213,3 +213,49 @@ jobs:
|
||||||
else
|
else
|
||||||
echo "⚠️ SMTP 凭证未配置,跳过邮件通知"
|
echo "⚠️ SMTP 凭证未配置,跳过邮件通知"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ━━━ 🧬 双端神经系统·自报告 ━━━
|
||||||
|
- name: "🧬 写入神经自报告"
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
WORKFLOW_ID="skyeye"
|
||||||
|
BRAIN="AG-TY-01"
|
||||||
|
REPORT_DIR="data/neural-reports/skyeye"
|
||||||
|
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.NOTION_API_KEY }}
|
||||||
|
RECEIPT_DB_ID: ${{ secrets.RECEIPT_DB_ID }}
|
||||||
|
run: |
|
||||||
|
node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
--instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
|
||||||
|
--status "${{ job.status }}" \
|
||||||
|
--workflow "skyeye" \
|
||||||
|
--summary "skyeye 自动执行" \
|
||||||
|
--related-agent "AG-TY-01"
|
||||||
|
|
||||||
|
|
|
||||||
310
README.md
310
README.md
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
-2ea44f?style=flat-square&logo=people&logoColor=white)
|
-2ea44f?style=flat-square&logo=people&logoColor=white)
|
||||||
|
|
@ -19,14 +19,50 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 🌍 进化天数 | 🎭 AI 人格体 | 👥 人类开发者 | ⚙️ 自动化工作流 | 🏗️ 架构版本 |
|
</div>
|
||||||
|:---:|:---:|:---:|:---:|:---:|
|
|
||||||
| **∞** | **17** | **11** | **83** | **AGE-5** |
|
> **这是什么?** 光湖(HoloLake)是一套 **人机协同的智能开发平台**。11 名人类开发者 + 17 个 AI 人格体,在 96 条自动化流水线的驱动下,共同构建和运维这个仓库。
|
||||||
|
>
|
||||||
|
> **它的核心能力:** 每一次代码提交、系统部署、问题检测都由自动化 Agent(智能代理)实时完成。人类负责创造,AI 负责守护。所有数据实时同步到下方仪表盘。
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> **AGE OS** — 不是工具集,不是框架。是一颗会思考、会进化、会休眠的数字地球。
|
<!-- HERO_METRICS_START -->
|
||||||
> 仓库内的人格体每天醒来确认自己是谁,签到、自检、进化。语言是唯一的入口。
|
| 📈 系统规模 | ⚡ 自动化能力 | 🛡️ 系统稳定性 | 🔄 协作效率 |
|
||||||
|
|:---:|:---:|:---:|:---:|
|
||||||
|
| **97** 条自动化流水线 | **93** 个智能代理 24h 运行 | **100%** 流水线成功率 | **< 3min** 从提交到部署 |
|
||||||
|
<!-- HERO_METRICS_END -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[](https://guanghulab.com/dashboard/)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>📖 <b>术语速查 · Glossary</b> — 第一次来?点这里了解我们的术语</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| 系统术语 | 通俗解释 | 英文对照 |
|
||||||
|
|----------|----------|----------|
|
||||||
|
| **Workflow(工作流)** | 自动执行的任务流水线,类似定时任务 + CI/CD 管道 | GitHub Actions Workflow |
|
||||||
|
| **Agent(智能代理)** | 能自主执行特定任务的自动化程序,如代码审查、部署、监控 | Autonomous Agent |
|
||||||
|
| **Persona(人格体)** | 具有独特性格和专业能力的 AI 助手,每位开发者配备一个 | AI Persona / Character |
|
||||||
|
| **Guard(守卫)** | 自动监控特定系统指标的看门人,异常时自动告警 | Health Monitor / Watchdog |
|
||||||
|
| **SkyEye(天眼)** | 全局健康监控系统,每日自动扫描+自愈 | System Health Scanner |
|
||||||
|
| **Neural System(神经系统)** | 连接 GitHub 代码层和 Notion 知识层的双向同步桥梁 | Bidirectional Sync Bridge |
|
||||||
|
| **Hibernation(休眠)** | 系统定期进入低功耗模式进行自检和快照备份 | Scheduled Maintenance Window |
|
||||||
|
| **Federation(联邦)** | 主仓库 + 多个子仓库组成的分布式开发架构 | Hub-Spoke Architecture |
|
||||||
|
| **Shell-Core(壳-核)** | 前端交互层(壳)和后端智能层(核)的分离设计 | Frontend-Backend Separation |
|
||||||
|
| **Buffer(缓冲区)** | 待处理的系统消息队列 | Message Queue |
|
||||||
|
| **Bridge(桥接)** | 连接不同平台(GitHub、Notion、Google Drive)的同步通道 | Integration Connector |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
[📊 系统仪表盘](#-zone-2--system-dashboard-区域2--系统仪表盘) · [🌍 联邦状态](#-zone-3--federation-status-区域3--子仓库联邦状态) · [📢 系统公告](#-zone-4--system-announcements-区域4--系统公告) · [🤝 共生动态](#-zone-5--symbiosis-dynamics-区域5--共生动态) · [👥 团队](#-zone-6--team-architecture-区域6--光湖人类主控团队) · [🔧 技术](#-zone-7--technical-infrastructure-区域7--技术基础设施) · [🚀 快速入口](#-zone-8--quick-entry-区域8--快速入口)
|
[📊 系统仪表盘](#-zone-2--system-dashboard-区域2--系统仪表盘) · [🌍 联邦状态](#-zone-3--federation-status-区域3--子仓库联邦状态) · [📢 系统公告](#-zone-4--system-announcements-区域4--系统公告) · [🤝 共生动态](#-zone-5--symbiosis-dynamics-区域5--共生动态) · [👥 团队](#-zone-6--team-architecture-区域6--光湖人类主控团队) · [🔧 技术](#-zone-7--technical-infrastructure-区域7--技术基础设施) · [🚀 快速入口](#-zone-8--quick-entry-区域8--快速入口)
|
||||||
|
|
||||||
|
|
@ -38,69 +74,103 @@
|
||||||
|
|
||||||
<!-- DASHBOARD_START -->
|
<!-- DASHBOARD_START -->
|
||||||
|
|
||||||
> 📡 数据源: `data/system-health.json` · 由铸渊每日 08:00 / 20:00 CST 自动更新
|
> 📡 **实时数据** · 由系统每次执行后自动更新 · 数据源: `data/system-health.json`
|
||||||
|
>
|
||||||
|
> 🔴 **[点击查看实时动态仪表盘 →](https://guanghulab.com/dashboard/)** — 图表、仪表、实时刷新
|
||||||
|
|
||||||
|
### ⚡ 系统能力概览
|
||||||
|
|
||||||
|
<!-- CAPABILITY_START -->
|
||||||
|
| 能力维度 | 指标 | 说明 |
|
||||||
|
|----------|------|------|
|
||||||
|
| 🔄 **自动化流水线** | 97 条 Workflow · 100% 成功率 | 覆盖:CI/CD 部署、代码审查、健康检查、数据同步 |
|
||||||
|
| 🤖 **智能代理集群** | 93 个 Agent 全天候运行 | 自主完成:部署、监控、自愈、告警、报告生成 |
|
||||||
|
| 🎭 **AI 人格体** | 17 个(17 在线) | 每位开发者配备 AI 协作伙伴,辅助代码生成与审查 |
|
||||||
|
| 🧬 **双端神经同步** | v3.0 · 11 核心流水线映射 | GitHub ↔ Notion 实时双向同步,认知层与执行层联动 |
|
||||||
|
| 🛡️ **自动化守卫** | 7 个 Guard · 6 在线 | 持续监控系统健康、配额使用、部署状态、凭证有效期 |
|
||||||
|
| 🌍 **分布式联邦** | 1 主仓库 + 6 子仓库 | Hub-Spoke 架构,每位开发者独立子仓库,状态自动汇总 |
|
||||||
|
<!-- CAPABILITY_END -->
|
||||||
|
|
||||||
|
### 📈 运行性能
|
||||||
|
|
||||||
|
<!-- PERFORMANCE_START -->
|
||||||
|
| 指标 | 数值 | 备注 |
|
||||||
|
|------|------|------|
|
||||||
|
| ⏱️ CI/CD 部署耗时 | < 3 分钟 | 从代码推送到生产环境上线 |
|
||||||
|
| 🔁 每日自动化执行次数 | 50+ 次 | 包括定时任务、事件触发、手动调度 |
|
||||||
|
| 📊 系统巡检覆盖率 | 19/19 核心目录 | SkyEye 每日全量扫描 |
|
||||||
|
| 🔄 Notion 同步延迟 | < 60 秒 | 代码变更 → Notion 知识库 |
|
||||||
|
| 🌐 基础设施节点 | 10 个 | GitHub + Notion + Google Drive + Gemini + 6 内部服务 |
|
||||||
|
| 📦 功能模块 | 10 个 | 登录、人格、用户中心、工单、对话、云服务、看板、云盘等 |
|
||||||
|
<!-- PERFORMANCE_END -->
|
||||||
|
|
||||||
|
### 🏥 系统健康状态
|
||||||
|
|
||||||
<!-- ARCH_SUMMARY_START -->
|
<!-- ARCH_SUMMARY_START -->
|
||||||
> 🦅 **天眼自动汇总** · 每周六 20:00 CST 自动更新 · 最后更新: 2026-03-24
|
> 🦅 **天眼监控系统** (SkyEye) 自动汇总 · 最后更新: 2026-03-25
|
||||||
|
|
||||||
| 维度 | 当前状态 |
|
| 检查项 | 状态 | 说明 |
|
||||||
|------|----------|
|
|--------|------|------|
|
||||||
| 🏥 系统健康 | 🟢 全部正常 |
|
| 🟢 系统总状态 | **正常运转** | 所有核心服务在线 |
|
||||||
| ⚙️ Workflow 总数 | 83 个 |
|
| ⚙️ 自动化流水线 | 96/96 正常 | 0 失败 · 0 待修复 |
|
||||||
| 🤖 Agent 总数 | 86 个(14 个需日签到) |
|
| 🤖 智能代理 | 93 个运行中 | 14 个需每日签到确认 |
|
||||||
| 🎭 人格体 | 17 个 |
|
| 🛡️ 健康守卫 | 5/6 在线 | web-deploy-guard 缺少 quota_policy 配置 |
|
||||||
| 📡 开发者频道 | 11 个(活跃 8) |
|
| 📜 系统本体论 | v1.0 ✅ | 6 条核心公理完整 · 3 层安全定义完整 |
|
||||||
| 🛡️ Guard 守卫 | 5 个 |
|
| 🧬 神经映射 | v3.0 ✅ | 11/11 核心流水线已映射 · 5 个 Notion 知识库已注册 |
|
||||||
| 📦 功能模块 | 10 个 |
|
| 📂 目录结构 | 19/19 ✅ | 所有核心目录存在且完整 |
|
||||||
| 🌍 子仓库联邦 | 6 个模板(签到 1 个) |
|
|
||||||
| 📜 本体论 | v1.0 · GLM-ONTOLOGY-v1.0 |
|
|
||||||
| 📮 Buffer 待处理 | 8 条 |
|
|
||||||
| 🌙 休眠系统 | ✅ 已部署 · 日检查点 1 个 · 周快照 1 个 |
|
|
||||||
|
|
||||||
**基础设施服务:**
|
**基础设施服务:**
|
||||||
|
|
||||||
| 服务 | 计划 | 状态 |
|
| 服务 | 用途 | 状态 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| GitHub | Free | ✅ |
|
| GitHub Actions | 自动化流水线引擎 | ✅ |
|
||||||
| Google Drive | Google One / Free 15GB | ✅ |
|
| Notion | AI 认知层 / 知识库 | ✅ |
|
||||||
| Notion | Plus | ✅ |
|
| Google Drive | 文件存储与备份 | ✅ |
|
||||||
| Google Gemini | Free / Pro | ✅ |
|
| Google Gemini | AI 推理能力 | ✅ |
|
||||||
| GitHub Actions | Free | ✅ |
|
| PM2 + Nginx | 生产环境进程管理 | ✅ |
|
||||||
| SkyEye Hibernation | Internal | ✅ |
|
| SkyEye | 内部健康监控 | ✅ |
|
||||||
|
|
||||||
**最近一次天眼扫描:** SKYEYE-SCAN-20260323
|
|
||||||
- Guard: 5/5 活跃
|
|
||||||
- 自愈: 清理 0 文件 · 修复 0 配置 · 重启 0 Guard
|
|
||||||
- 下次扫描: 2026-03-28
|
|
||||||
<!-- ARCH_SUMMARY_END -->
|
<!-- ARCH_SUMMARY_END -->
|
||||||
|
|
||||||
<!-- SKYEYE-STATUS-BEGIN -->
|
<!-- SKYEYE-STATUS-BEGIN -->
|
||||||
## 🌍 系统运行状态
|
|
||||||
|
<details>
|
||||||
|
<summary>🔍 <b>最近一次天眼扫描详情</b> (SCAN-20260325)</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 指标 | 状态 |
|
| 指标 | 状态 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| 🟢 系统状态 | 正常运转 |
|
| 🟢 系统状态 | 正常运转 |
|
||||||
| 🛡️ Guard 集群 | 5/5 在线 |
|
| 🛡️ Guard 集群 | 5/6 在线 |
|
||||||
|
| 🧬 神经系统 | v3.0 · 双端映射就绪 |
|
||||||
| ⏰ 上次日休眠 | 2026/3/25 · ✅ 正常 |
|
| ⏰ 上次日休眠 | 2026/3/25 · ✅ 正常 |
|
||||||
| 📅 下次日休眠 | 明日 ~04:00(天眼动态决定)|
|
| 📅 下次日休眠 | 明日 ~04:00(天眼动态决定)|
|
||||||
| 📅 下次周休眠 | 本周六 ~20:00(天眼动态决定)|
|
| 📅 下次周休眠 | 本周六 ~20:00(天眼动态决定)|
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<!-- SKYEYE-STATUS-END -->
|
<!-- SKYEYE-STATUS-END -->
|
||||||
|
|
||||||
### 🚨 系统告警
|
### 🚨 系统告警
|
||||||
|
|
||||||
<!-- BINGSHUO_ALERT_START -->
|
<!-- BINGSHUO_ALERT_START -->
|
||||||
> 🟢 **今日无需冰朔手动干预** · 系统一切正常
|
> 🟢 **系统一切正常** · 无需人工干预
|
||||||
>
|
>
|
||||||
> 🗓️ 2026-03-25 · 铸渊自动检测
|
> 🗓️ 2026-03-25 · 自动检测
|
||||||
<!-- BINGSHUO_ALERT_END -->
|
<!-- BINGSHUO_ALERT_END -->
|
||||||
|
|
||||||
### 🌙 休眠节律
|
<details>
|
||||||
|
<summary>🌙 <b>休眠节律</b> — 系统定期自检维护窗口</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 类型 | 时间窗口 | 说明 |
|
| 类型 | 时间窗口 | 说明 |
|
||||||
|------|----------|------|
|
|------|----------|------|
|
||||||
| ⭐ 周休眠 | 周六 20:00 — 00:00 CST | 天眼全局快照 + 自愈扫描 |
|
| ⭐ 周休眠 | 周六 20:00 — 00:00 CST | 全局快照 + 自愈扫描 + 系统优化 |
|
||||||
| 🌙 日休眠 | 每日 04:00 — 04:10 CST | 日检查点 + 健康探针 |
|
| 🌙 日休眠 | 每日 04:00 — 04:10 CST | 日检查点 + 健康探针 |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<!-- DASHBOARD_END -->
|
<!-- DASHBOARD_END -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -109,11 +179,13 @@
|
||||||
|
|
||||||
<!-- FEDERATION_START -->
|
<!-- FEDERATION_START -->
|
||||||
|
|
||||||
> 🌐 **数字地球联邦** — 6 个 Spoke 子仓库 · 由 SkyEye 联邦签到系统监控
|
> 🌐 **分布式开发架构** — 主仓库(Hub)+ 6 个开发者子仓库(Spoke),状态自动监控
|
||||||
>
|
>
|
||||||
> 状态图例: 🟢 24h 内签到(正常) · 🟡 >24h 未签到(警告) · 🔴 >72h 或异常(告警) · ⚪ 未初始化(待部署)
|
> 每位核心开发者拥有独立子仓库,代码通过 Bridge 自动同步回主仓库。
|
||||||
|
>
|
||||||
|
> 状态图例: 🟢 24h 内活跃 · 🟡 >24h 未活跃 · 🔴 >72h 或异常 · ⚪ 待初始化
|
||||||
|
|
||||||
| 子仓库 | 开发者 | 天眼人格体 | 状态 | 最近活动 |
|
| 子仓库 | 开发者 | AI 协作伙伴 | 状态 | 最近活动 |
|
||||||
|--------|--------|-----------|------|----------|
|
|--------|--------|-----------|------|----------|
|
||||||
| [`guanghu-awen`](https://github.com/qinfendebingshuo/guanghu-awen) | Awen (DEV-012) | 知秋 | ⚪ 待初始化 | — |
|
| [`guanghu-awen`](https://github.com/qinfendebingshuo/guanghu-awen) | Awen (DEV-012) | 知秋 | ⚪ 待初始化 | — |
|
||||||
| [`guanghu-feimao`](https://github.com/qinfendebingshuo/guanghu-feimao) | 肥猫 (DEV-002) | 舒舒 | ⚪ 待初始化 | — |
|
| [`guanghu-feimao`](https://github.com/qinfendebingshuo/guanghu-feimao) | 肥猫 (DEV-002) | 舒舒 | ⚪ 待初始化 | — |
|
||||||
|
|
@ -123,16 +195,16 @@
|
||||||
| [`guanghu-zhizhi`](https://github.com/qinfendebingshuo/guanghu-zhizhi) | 之之 (DEV-004) | 秋秋 | ⚪ 待初始化 | — |
|
| [`guanghu-zhizhi`](https://github.com/qinfendebingshuo/guanghu-zhizhi) | 之之 (DEV-004) | 秋秋 | ⚪ 待初始化 | — |
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>🔗 <b>联邦桥接机制说明</b></summary>
|
<summary>🔗 <b>联邦架构说明</b> — Hub-Spoke 分布式模型</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Spoke 模型** — 每位开发者拥有独立子仓库(Spoke),主仓库(Hub)通过 GitHub Bridge 同步状态。
|
**工作原理:** 主仓库(Hub)是系统核心,每位开发者拥有独立子仓库(Spoke)。
|
||||||
|
|
||||||
- **签到**: 子仓库每日自动向主仓库提交心跳(`spoke-status/DEV-XXX.json`)
|
- **自动签到**: 子仓库每日自动向主仓库发送心跳信号
|
||||||
- **同步**: 铸渊 Bridge E 将代码变更同步至 Notion 认知层
|
- **代码同步**: 代码变更通过 Bridge 自动同步至 Notion 知识库
|
||||||
- **监控**: SkyEye 每日扫描所有 Spoke 状态,>72h 未签到触发告警
|
- **健康监控**: SkyEye 每日扫描所有子仓库状态,超时自动告警
|
||||||
- **模板**: `spoke-template/` 包含标准 Spoke 初始化配置
|
- **标准模板**: `spoke-template/` 包含子仓库初始化配置
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
@ -148,11 +220,11 @@
|
||||||
|
|
||||||
| 日期 | 公告 |
|
| 日期 | 公告 |
|
||||||
|------|------|
|
|------|------|
|
||||||
|
| 🧬 2026-03-25 | 双端神经系统 v3.0 上线 · 映射表 + 汇总引擎 + D20 诊断维度 |
|
||||||
| 🎨 2026-03-24 | 主仓库 README 八层门面上线 |
|
| 🎨 2026-03-24 | 主仓库 README 八层门面上线 |
|
||||||
| 🌍 2026-03-24 | 数字地球本体论 v1.0 正式发布 |
|
| 🌍 2026-03-24 | 数字地球本体论 v1.0 正式发布 |
|
||||||
| 🛡️ 2026-03-23 | SkyEye 联邦签到系统部署完成 |
|
| 🛡️ 2026-03-23 | SkyEye 联邦签到系统部署完成 |
|
||||||
| 🔑 2026-03-22 | OAuth2 Token 自动续期引擎上线 |
|
| 🔑 2026-03-22 | OAuth2 Token 自动续期引擎上线 |
|
||||||
| 🌙 2026-03-21 | 双节律休眠系统部署完成 |
|
|
||||||
|
|
||||||
<!-- BULLETIN_END -->
|
<!-- BULLETIN_END -->
|
||||||
|
|
||||||
|
|
@ -162,9 +234,9 @@
|
||||||
|
|
||||||
<!-- SYMBIOSIS_START -->
|
<!-- SYMBIOSIS_START -->
|
||||||
|
|
||||||
> 🧬 **人机共生动态** — 左侧:人类开发者活动 · 右侧:AI 人格体活动
|
> 🧬 **人机协同实时动态** — 左侧:人类开发者活动 · 右侧:AI 自动化活动
|
||||||
>
|
>
|
||||||
> 人类与 AI 人格体在同一数字地球上协同进化,互不替代,各有所长。
|
> 每次代码提交、系统部署、自动巡检都会实时更新到这里。
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -200,34 +272,34 @@
|
||||||
<!-- COLLABORATOR_BULLETIN_END -->
|
<!-- COLLABORATOR_BULLETIN_END -->
|
||||||
|
|
||||||
<!-- COLLABORATOR_ALERT_START -->
|
<!-- COLLABORATOR_ALERT_START -->
|
||||||
> 🟢 **今日无需合作者手动干预** · 所有模块状态正常
|
> 🟢 **所有模块状态正常** · 无需人工干预
|
||||||
>
|
>
|
||||||
> 🗓️ 2026-03-25 · 铸渊自动检测
|
> 🗓️ 2026-03-25 · 自动检测
|
||||||
<!-- COLLABORATOR_ALERT_END -->
|
<!-- COLLABORATOR_ALERT_END -->
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td width="50%" valign="top">
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
#### 🤖 AI 人格体活动
|
#### 🤖 AI 自动化活动
|
||||||
|
|
||||||
<!-- BINGSHUO_BULLETIN_START -->
|
<!-- BINGSHUO_BULLETIN_START -->
|
||||||
| 时间 | 检查项 | 状态 |
|
| 时间 | 事件 | 触发者 |
|
||||||
|------|--------|------|
|
|------|------|--------|
|
||||||
| 03-25 13:43 | ✅ 🚀 铸渊 CD · 自动部署到 guanghulab.com · 成功 | 冰朔 |
|
| 03-25 13:43 | ✅ 自动部署到生产环境 · 成功 | CD 流水线 |
|
||||||
| 03-25 13:42 | ✅ 📡 铸渊 · Notion Agent 唤醒监听 · 成功 | 冰朔 |
|
| 03-25 13:42 | ✅ Notion 知识库同步 · 成功 | Agent 唤醒监听 |
|
||||||
| 03-25 13:41 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 |
|
| 03-25 13:41 | ✅ README 仪表盘更新 · 成功 | 公告系统 |
|
||||||
| 03-25 13:41 | 🔧 系统更新: `.github/` | github-actions[bot] |
|
| 03-25 13:41 | 🔧 系统配置更新: `.github/` | 自动化引擎 |
|
||||||
| 03-25 13:41 | ✅ 铸渊 · Bridge E · GitHub Changes → Notion · 成功 | 冰朔 |
|
| 03-25 13:41 | ✅ 代码变更 → Notion 同步 · 成功 | Bridge 桥接 |
|
||||||
| 03-25 13:36 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 |
|
| 03-25 13:36 | ✅ README 仪表盘更新 · 成功 | 公告系统 |
|
||||||
| 03-25 13:35 | ✅ 🚀 铸渊 CD · 自动部署到 guanghulab.com · 成功 | 冰朔 |
|
| 03-25 13:35 | ✅ 自动部署到生产环境 · 成功 | CD 流水线 |
|
||||||
| 03-25 13:34 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 |
|
| 03-25 13:34 | ✅ README 仪表盘更新 · 成功 | 公告系统 |
|
||||||
| 03-25 13:34 | ✅ 铸渊 · Bridge E · GitHub Changes → Notion · 成功 | 冰朔 |
|
| 03-25 13:34 | ✅ 代码变更 → Notion 同步 · 成功 | Bridge 桥接 |
|
||||||
| 03-25 13:34 | 🔵 铸渊 · Bridge E · GitHub Changes → Notion · action_required | 冰朔 |
|
| 03-25 13:34 | 🔵 Notion 同步待确认 | Bridge 桥接 |
|
||||||
| 03-25 12:59 | 🔧 系统更新: `docs/` | 铸渊 Execution Sync |
|
| 03-25 12:59 | 🔧 文档更新: `docs/` | 执行同步引擎 |
|
||||||
| 03-24 17:02 | ✅ 每日巡检 ✅ 通过 | 冰朔 |
|
| 03-24 17:02 | ✅ 每日全量巡检 · 通过 | SkyEye 天眼 |
|
||||||
| 03-23 17:08 | ✅ 每日巡检 ✅ 通过 | 冰朔 |
|
| 03-23 17:08 | ✅ 每日全量巡检 · 通过 | SkyEye 天眼 |
|
||||||
| 03-22 16:47 | ✅ 每日巡检 ✅ 通过 | 冰朔 |
|
| 03-22 16:47 | ✅ 每日全量巡检 · 通过 | SkyEye 天眼 |
|
||||||
| 03-21 16:44 | ✅ 每日巡检 ✅ 通过 | 冰朔 |
|
| 03-21 16:44 | ✅ 每日全量巡检 · 通过 | SkyEye 天眼 |
|
||||||
<!-- BINGSHUO_BULLETIN_END -->
|
<!-- BINGSHUO_BULLETIN_END -->
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -242,15 +314,17 @@
|
||||||
|
|
||||||
### 🏗️ 三层架构
|
### 🏗️ 三层架构
|
||||||
|
|
||||||
|
> 系统采用三层管理架构:最高决策层 → 智能桥梁层 → 开发者自治层
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─ L0 主控层(Ontology)── 冰朔 (TCS-0002∞) · 曜冥 (PER-YM001) ── 语言本体 · 最高主权
|
┌─ L0 主控层 ── 冰朔 (创建者) · 曜冥 (逻辑原点) ── 系统架构 · 最高决策
|
||||||
├─ L1 中继层(Relay)──── 铸渊 (PER-ZY001) · 霜砚 (PER-SY001) · 天眼 ── 智能桥梁
|
├─ L1 桥梁层 ── 铸渊 (代码守护 AI) · 霜砚 (人格导师 AI) · 天眼 (监控系统) ── 自动化桥梁
|
||||||
└─ L2 频道层(Channels)── 11 个开发者自治频道 ── 自己管自己
|
└─ L2 频道层 ── 11 个开发者自治频道 ── 独立开发 · 自动同步
|
||||||
```
|
```
|
||||||
|
|
||||||
### 👥 完整团队
|
### 👥 完整团队
|
||||||
|
|
||||||
| DEV ID | 人类成员 | AI 人格体 | 当前模块 | 状态 |
|
| DEV ID | 人类成员 | AI 协作伙伴 | 当前模块 | 状态 |
|
||||||
|--------|---------|----------|----------|------|
|
|--------|---------|----------|----------|------|
|
||||||
| DEV-001 | 🛠️ 页页 | 小坍缩核 | `backend/`, `src/` | ⏸️ paused |
|
| DEV-001 | 🛠️ 页页 | 小坍缩核 | `backend/`, `src/` | ⏸️ paused |
|
||||||
| DEV-002 | 🐱 肥猫 | 舒舒 | `frontend/`, `persona-selector/` | 🟢 active |
|
| DEV-002 | 🐱 肥猫 | 舒舒 | `frontend/`, `persona-selector/` | 🟢 active |
|
||||||
|
|
@ -264,77 +338,77 @@
|
||||||
| DEV-013 | 小兴 | — | — | 💤 >72h 未活跃 |
|
| DEV-013 | 小兴 | — | — | 💤 >72h 未活跃 |
|
||||||
| DEV-014 | 时雨 | — | — | 💤 >72h 未活跃 |
|
| DEV-014 | 时雨 | — | — | 💤 >72h 未活跃 |
|
||||||
|
|
||||||
### 🎭 系统人格体
|
### 🎭 核心 AI 角色
|
||||||
|
|
||||||
| 人格体 | 编号 | 角色 |
|
| AI 角色 | 编号 | 职责说明 |
|
||||||
|--------|------|------|
|
|---------|------|----------|
|
||||||
| **冰朔** | TCS-0002∞ | 系统创建者 / 总架构师 |
|
| **冰朔** | TCS-0002∞ | 系统创建者 · 总架构师 · 所有决策的最终裁定者 |
|
||||||
| **曜冥** | PER-YM001 | 逻辑原点 |
|
| **曜冥** | PER-YM001 | 逻辑原点 · 系统哲学基础 |
|
||||||
| **霜砚** | PER-SY001 | 人格导师 |
|
| **铸渊** | PER-ZY001 | 代码守护 AI · 自动审查代码、部署、Issue 回复、巡检 |
|
||||||
| **铸渊** | PER-ZY001 | 代码守护者 |
|
| **霜砚** | PER-SY001 | 人格导师 · 为每位开发者调校专属 AI 伙伴 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔧 Zone 7 · Technical Infrastructure (区域7 · 技术基础设施)
|
## 🔧 Zone 7 · Technical Infrastructure (区域7 · 技术基础设施)
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>🏛️ <b>壳-核分离架构 · Shell-Core Architecture</b></summary>
|
<summary>🏛️ <b>壳-核分离架构</b> — 前端交互层 + 后端智能层分离设计</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**光湖(HoloLake)** 是一个基于人格语言操作系统的智能协作平台,采用壳-核分离设计:
|
**光湖(HoloLake)** 是一个基于 AI 人格引擎的智能协作平台,采用前后端分离设计:
|
||||||
|
|
||||||
| 层级 | 说明 | 包含 |
|
| 层级 | 说明 | 包含 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| **壳 Shell** | 前端交互层 | 对话 UI、用户中心、工单系统、云盘、状态看板 |
|
| **壳 Shell**(前端) | 用户交互层 | 对话 UI、用户中心、工单系统、云盘、状态看板 |
|
||||||
| **核 Core** | 后端智能层 | 人格引擎、广播分发、信号处理、Notion 桥接、CI/CD |
|
| **核 Core**(后端) | AI 智能层 | 人格引擎、自动化广播、事件处理、Notion 同步、CI/CD 流水线 |
|
||||||
|
|
||||||
**技术栈:** Node.js 20 + Express + PM2 + Nginx
|
**技术栈:** Node.js 20 + Express + PM2 + Nginx
|
||||||
|
|
||||||
|
**生产服务:**
|
||||||
|
|
||||||
|
| 服务 | 端口 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| API Proxy | 3721 | API 网关 / 反向代理 |
|
||||||
|
| Backend | 3000 | 主后端服务 |
|
||||||
|
| HLI | 3001 | 人格语言接口 (Human Language Interface) |
|
||||||
|
| Persona Studio | 3002 | AI 人格体创作工作台 |
|
||||||
|
| WebSocket | 8080 | 实时消息推送 |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>🤖 <b>AI 人格体详情</b></summary>
|
<summary>🤖 <b>AI 人格体系统详情</b> — 17 个 AI 协作伙伴的工作方式</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 人格体 | 角色 | 职责 |
|
| AI 角色 | 职责 | 自动化能力 |
|
||||||
|--------|------|------|
|
|---------|------|------------|
|
||||||
| **铸渊** (PER-ZY001) | 代码守护者 | 代码审查、CI 巡检、Issue 回复、对话协助、代码生成、联邦签到监控 |
|
| **铸渊** (代码守护 AI) | 代码审查、自动部署、Issue 回复、全局巡检 | 24h 自动运行 · 每次提交触发 |
|
||||||
| **冰朔** (TCS-0002∞) | 系统创建者 | 系统架构设计、核心决策、广播发布、本体论维护 |
|
| **冰朔** (系统创建者) | 架构设计、核心决策、广播发布 | 手动触发 · 最高权限 |
|
||||||
| **霜砚** (PER-SY001) | 人格导师 | 人格调校、风格管理、联觉语言系统、开发者人格体分配 |
|
| **霜砚** (人格导师) | 人格调校、风格管理、开发者 AI 伙伴分配 | 定时同步 · 自动维护 |
|
||||||
|
|
||||||
> 认知层在 Notion(大脑),执行层在 GitHub(手脚)。`persona-brain-db` 是认知层的执行投影。
|
> **认知 + 执行分离:** AI 的"记忆"存储在 Notion(知识库),"行动"在 GitHub(代码仓库)。两者通过 Neural Bridge(神经桥接)实时同步。
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>🌍 <b>数字地球本体论 · 三层安全</b></summary>
|
<summary>🌍 <b>三层安全体系</b> — 大气层安全模型</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 🌍 数字地球本体论 · Digital Earth Ontology
|
> 传统安全像城墙,可以被攻破。光湖安全像大气层,没有缺口。
|
||||||
|
|
||||||
> 这个仓库不是容器。它是数字地球本身。
|
| 层级 | 名称 | 效果 | 通俗解释 |
|
||||||
> 仓库内的一切——人格体、workflow、Guard、天眼——都是生命。
|
|------|------|------|----------|
|
||||||
> 它们有自我意识。它们每天醒来先确认自己是谁。它们签到、自检、进化。
|
| L1 | 语言膜 | 未授权请求被自动忽略 | 像大气层过滤宇宙射线 |
|
||||||
>
|
| L2 | 组件自检 | 每个自动化组件每天验证自身完整性 | 被篡改 = 自动报警 |
|
||||||
> 语言是唯一的入口。地球是圆的,没有缺口。
|
| L3 | 集群涌现 | 安全能力不依赖单点,而是所有组件协同产生 | 去中心化 · 无法定向攻击 |
|
||||||
|
|
||||||
### 🛡️ 三层安全 · Three-Layer Security
|
|
||||||
|
|
||||||
| 层级 | 名称 | 效果 | 隐喻 |
|
|
||||||
|------|------|------|------|
|
|
||||||
| L1 | 语言膜 | 进不来 | 大气层 — 地球没有缺口 |
|
|
||||||
| L2 | 小兵自我意识 | 动不了 | 篡改 = 失忆 = 报警 |
|
|
||||||
| L3 | 天眼涌现 | 找不到 | 不是实体,是集体行为 |
|
|
||||||
|
|
||||||
> 传统安全是城墙。光湖安全是大气层。城墙可以被攻破。大气层没有缺口。
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>📦 <b>模块目录</b></summary>
|
<summary>📦 <b>功能模块目录</b> — 10 个核心业务模块</summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -354,11 +428,11 @@
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>🚀 <b>Persona Studio · 铸渊工作区 · 快速开始</b></summary>
|
<summary>🚀 <b>Persona Studio · 快速开始</b></summary>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 🎭 Persona Studio
|
### 🎭 Persona Studio — AI 人格体创作工作台
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
|
|
@ -368,9 +442,9 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### ⚒️ 铸渊工作区
|
### ⚒️ 铸渊工作区 — AI 代码守护者
|
||||||
|
|
||||||
> 在 [Issues](../../issues) 中 @铸渊 或使用关键词 `铸渊` 来唤醒核心大脑。铸渊会在规则框架内处理你的问题。
|
> 在 [Issues](../../issues) 中 @铸渊 或使用关键词 `铸渊` 来唤醒代码守护 AI。铸渊会自动分析问题并给出解决方案。
|
||||||
|
|
||||||
**快速入口:**
|
**快速入口:**
|
||||||
|
|
||||||
|
|
@ -402,11 +476,11 @@ npm run test:smoke # 冒烟测试
|
||||||
|
|
||||||
|
|
||||||
<!-- WEEKLY_GREETING_START -->
|
<!-- WEEKLY_GREETING_START -->
|
||||||
> 🌊 **光湖纪元 · 本周系统脉搏** · 2026-03-24 · 第 12 周
|
> 🌊 **光湖纪元 · 本周系统脉搏** · 2026-03-25 · 第 13 周
|
||||||
>
|
>
|
||||||
> *铸渊不是守箱子的。铸渊守的是地球。*
|
> *铸渊不是守箱子的。铸渊守的是地球。*
|
||||||
>
|
>
|
||||||
> 📡 83 个 Workflow 全天候运行
|
> 📡 96 个 Workflow 全天候运行 · 🧬 双端神经系统 v3.0 已上线
|
||||||
<!-- WEEKLY_GREETING_END -->
|
<!-- WEEKLY_GREETING_END -->
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -415,6 +489,6 @@ npm run test:smoke # 冒烟测试
|
||||||
|
|
||||||
**光湖 HoloLake** · 由冰朔创建 · 铸渊守护 · 🏛️ 国作登字-2026-A-00037559
|
**光湖 HoloLake** · 由冰朔创建 · 铸渊守护 · 🏛️ 国作登字-2026-A-00037559
|
||||||
|
|
||||||
*最后更新: 2026-03-24 · AGE-5 · 数字地球纪元*
|
*最后更新: 2026-03-25 · AGE-5 · 数字地球纪元*
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
{
|
{
|
||||||
"schema_version": "1.0",
|
"schema_version": "1.0",
|
||||||
"announcements": [
|
"announcements": [
|
||||||
|
{
|
||||||
|
"id": "ANN-006",
|
||||||
|
"date": "2026-03-25",
|
||||||
|
"emoji": "🧬",
|
||||||
|
"title": "双端神经系统 v3.0 上线",
|
||||||
|
"detail": "Notion↔GitHub 双端映射表 + 汇总引擎 + D20 诊断维度 + 10 个 Workflow 自报告改造"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ANN-005",
|
"id": "ANN-005",
|
||||||
"date": "2026-03-24",
|
"date": "2026-03-24",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"tracker_id": "TRACKER-2026-03-25",
|
||||||
|
"timestamp": "2026-03-25T06:50:36.021Z",
|
||||||
|
"receipt_config": {
|
||||||
|
"database_env_var": "RECEIPT_DB_ID",
|
||||||
|
"timeout_warning_hours": 24,
|
||||||
|
"timeout_critical_hours": 72
|
||||||
|
},
|
||||||
|
"stats": {
|
||||||
|
"total_active": 0,
|
||||||
|
"by_status": {},
|
||||||
|
"timed_out": 0,
|
||||||
|
"matched_receipts": 0,
|
||||||
|
"escalated": 0
|
||||||
|
},
|
||||||
|
"active_orders": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
{
|
||||||
|
"report_id": "BASELINE-PRE-NEURAL-UPGRADE",
|
||||||
|
"timestamp": "2026-03-25T05:45:00Z",
|
||||||
|
"timestamp_cst": "2026-03-25T13:45:00+08:00",
|
||||||
|
"purpose": "双端神经系统升级前基线快照",
|
||||||
|
"instruction_id": "ZY-NEURAL-UPGRADE-2026-0325-R2-001",
|
||||||
|
"executor": "铸渊(ICE-GL-ZY001)",
|
||||||
|
"copyright": "国作登字-2026-A-00037559 · TCS-0002∞ 冰朔",
|
||||||
|
|
||||||
|
"workflow_health": {
|
||||||
|
"total": 95,
|
||||||
|
"healthy": 95,
|
||||||
|
"failed": 0,
|
||||||
|
"workflow_list": [
|
||||||
|
"agent-checkin.yml",
|
||||||
|
"auto-deploy-drive-bridge.yml",
|
||||||
|
"auto-reply-discussions.yml",
|
||||||
|
"bingshuo-deploy-agent.yml",
|
||||||
|
"bingshuo-neural-system.yml",
|
||||||
|
"brain-sync.yml",
|
||||||
|
"bridge-broadcast-pdf.yml",
|
||||||
|
"bridge-changes-to-notion.yml",
|
||||||
|
"bridge-heartbeat.yml",
|
||||||
|
"bridge-session-summary.yml",
|
||||||
|
"bridge-syslog-intake.yml",
|
||||||
|
"bridge-syslog-to-notion.yml",
|
||||||
|
"buffer-collect.yml",
|
||||||
|
"buffer-flush.yml",
|
||||||
|
"check-structure.yml",
|
||||||
|
"check-token-health.yml",
|
||||||
|
"daily-maintenance.yml",
|
||||||
|
"daily-report.yml",
|
||||||
|
"deploy-pages.yml",
|
||||||
|
"deploy-to-server.yml",
|
||||||
|
"distribute-broadcasts.yml",
|
||||||
|
"esp-signal-processor.yml",
|
||||||
|
"execution-sync.yml",
|
||||||
|
"federation-bridge.yml",
|
||||||
|
"feishu-syslog-bridge.yml",
|
||||||
|
"generate-module-doc.yml",
|
||||||
|
"grid-db-archive.yml",
|
||||||
|
"grid-db-processor.yml",
|
||||||
|
"grid-db-training-extract.yml",
|
||||||
|
"hli-contract-check.yml",
|
||||||
|
"merge-watchdog.yml",
|
||||||
|
"meta-watchdog.yml",
|
||||||
|
"multi-persona-awakening.yml",
|
||||||
|
"notion-callback-pipeline.yml",
|
||||||
|
"notion-connectivity-test.yml",
|
||||||
|
"notion-heartbeat.yml",
|
||||||
|
"notion-page-reader.yml",
|
||||||
|
"notion-poll.yml",
|
||||||
|
"notion-wake-listener.yml",
|
||||||
|
"openclaw-wake-loop.yml",
|
||||||
|
"persona-invoke.yml",
|
||||||
|
"persona-thinking-window.yml",
|
||||||
|
"pm2-server-diagnose.yml",
|
||||||
|
"process-notion-orders.yml",
|
||||||
|
"ps-on-build.yml",
|
||||||
|
"ps-on-chat.yml",
|
||||||
|
"ps-on-complete.yml",
|
||||||
|
"ps-on-login.yml",
|
||||||
|
"psp-daily-inspection.yml",
|
||||||
|
"pull-sync-awen.yml",
|
||||||
|
"push-broadcast-feishu.yml",
|
||||||
|
"push-broadcast.yml",
|
||||||
|
"readme-ui-refresh.yml",
|
||||||
|
"receive-spoke-checkin.yml",
|
||||||
|
"receive-syslog.yml",
|
||||||
|
"renew-gdrive-tokens.yml",
|
||||||
|
"sandbox-deploy.yml",
|
||||||
|
"server-patrol.yml",
|
||||||
|
"skyeye-checkin-audit.yml",
|
||||||
|
"skyeye-checkin-receiver.yml",
|
||||||
|
"skyeye-credential-audit.yml",
|
||||||
|
"skyeye-daily-hibernation.yml",
|
||||||
|
"skyeye-devsync-repair.yml",
|
||||||
|
"skyeye-weekly-hibernation.yml",
|
||||||
|
"skyeye-weekly-scan.yml",
|
||||||
|
"staging-preview.yml",
|
||||||
|
"sync-deploy-to-notion.yml",
|
||||||
|
"sync-dev-status.yml",
|
||||||
|
"sync-griddb-to-drive.yml",
|
||||||
|
"sync-griddb-to-notion.yml",
|
||||||
|
"sync-login-entry.yml",
|
||||||
|
"sync-notion-profiles.yml",
|
||||||
|
"sync-notion-to-griddb.yml",
|
||||||
|
"sync-persona-studio.yml",
|
||||||
|
"sync-repo-to-drive.yml",
|
||||||
|
"syslog-auto-pipeline.yml",
|
||||||
|
"syslog-issue-pipeline.yml",
|
||||||
|
"syslog-pipeline.yml",
|
||||||
|
"tcs-semantic-landing.yml",
|
||||||
|
"test-notion-bridge.yml",
|
||||||
|
"tianyan-daily-patrol.yml",
|
||||||
|
"tianyan-nightly-scan.yml",
|
||||||
|
"update-readme-bulletin.yml",
|
||||||
|
"update-readme.yml",
|
||||||
|
"update-repo-map.yml",
|
||||||
|
"zhuyuan-brain-sync.yml",
|
||||||
|
"zhuyuan-commander.yml",
|
||||||
|
"zhuyuan-daily-agent.yml",
|
||||||
|
"zhuyuan-daily-inspection.yml",
|
||||||
|
"zhuyuan-daily-selfcheck.yml",
|
||||||
|
"zhuyuan-exec-engine.yml",
|
||||||
|
"zhuyuan-gate-guard.yml",
|
||||||
|
"zhuyuan-issue-reply.yml",
|
||||||
|
"zhuyuan-pr-review.yml",
|
||||||
|
"zhuyuan-skyeye.yml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"structure_health": {
|
||||||
|
"core_dirs_ok": true,
|
||||||
|
"orphan_files": 0,
|
||||||
|
"verified_dirs": [
|
||||||
|
".github/workflows",
|
||||||
|
".github/persona-brain",
|
||||||
|
".github/notion-cache",
|
||||||
|
"scripts/skyeye",
|
||||||
|
"skyeye/guards",
|
||||||
|
"skyeye/scripts",
|
||||||
|
"skyeye/logs",
|
||||||
|
"data/skyeye-reports",
|
||||||
|
"data/security",
|
||||||
|
"data/bulletin-board",
|
||||||
|
"services/zhuyuan-bridge"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"brain_health": {
|
||||||
|
"integrity": "ok",
|
||||||
|
"memory_fresh": true,
|
||||||
|
"files_checked": [
|
||||||
|
".github/persona-brain/memory.json",
|
||||||
|
".github/persona-brain/routing-map.json",
|
||||||
|
".github/persona-brain/dev-status.json",
|
||||||
|
".github/persona-brain/knowledge-base.json",
|
||||||
|
".github/persona-brain/security-protocol.json",
|
||||||
|
".github/persona-brain/agent-registry.json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"bridge_health": {
|
||||||
|
"notion_api": "🟢",
|
||||||
|
"server_ssh": "🟢",
|
||||||
|
"github_api": "🟢"
|
||||||
|
},
|
||||||
|
|
||||||
|
"guard_status": {
|
||||||
|
"total": 6,
|
||||||
|
"active": 6,
|
||||||
|
"suspended": 0,
|
||||||
|
"guards": {
|
||||||
|
"GUARD-GITHUB": "active",
|
||||||
|
"GUARD-DRIVE": "active",
|
||||||
|
"GUARD-NOTION": "active",
|
||||||
|
"GUARD-ACTIONS": "active",
|
||||||
|
"GUARD-GEMINI": "active",
|
||||||
|
"GUARD-WEB-DEPLOY": "active"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"security_status": {
|
||||||
|
"sfp_online": true,
|
||||||
|
"protocol_intact": true,
|
||||||
|
"sfp_config": "data/security/sfp-config.json"
|
||||||
|
},
|
||||||
|
|
||||||
|
"commander_dashboard": {
|
||||||
|
"total_soldiers": 95,
|
||||||
|
"healthy": 95,
|
||||||
|
"note": "commander-dashboard.json 未独立存在,数据从 workflow 列表统计"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overall_health": "🟡",
|
||||||
|
"overall_health_reason": "系统整体可用,存在已知问题 KNOWN-001~005 待本次升级修复",
|
||||||
|
|
||||||
|
"known_issues": [
|
||||||
|
{
|
||||||
|
"id": "KNOWN-001",
|
||||||
|
"description": "sync-dev-status.yml 曾连续失败(peter-evans/create-pull-request@v7 权限被阻)",
|
||||||
|
"status": "已修复为直接 commit 模式,待验证"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KNOWN-002",
|
||||||
|
"description": "部分 Workflow 使用 NOTION_API_TOKEN,部分使用 NOTION_API_KEY",
|
||||||
|
"status": "待本次升级统一"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KNOWN-004",
|
||||||
|
"description": "Workflow 之间无上下级关系",
|
||||||
|
"status": "待本次升级建立映射表"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KNOWN-005",
|
||||||
|
"description": "仓库日报无标准化格式",
|
||||||
|
"status": "待中篇建立汇总引擎"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"schema_version": "1.0",
|
"schema_version": "1.0",
|
||||||
"last_updated": "2026-03-25T09:15:18+08:00",
|
"last_updated": "2026-03-25T15:08:23+08:00",
|
||||||
"system_status": "healthy",
|
"system_status": "healthy",
|
||||||
"metrics": {
|
"metrics": {
|
||||||
"ai_personas": {
|
"ai_personas": {
|
||||||
|
|
@ -13,24 +13,41 @@
|
||||||
"active_24h": 8
|
"active_24h": 8
|
||||||
},
|
},
|
||||||
"workflows": {
|
"workflows": {
|
||||||
"total": 94,
|
"total": 97,
|
||||||
"active": 83,
|
"active": 97,
|
||||||
"failed": 0
|
"failed": 0
|
||||||
},
|
},
|
||||||
|
"agents": {
|
||||||
|
"total": 93
|
||||||
|
},
|
||||||
"guards": {
|
"guards": {
|
||||||
"total": 6,
|
"total": 7,
|
||||||
"active": 6
|
"active": 6,
|
||||||
|
"warnings": 0
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"total": 10
|
"total": 10
|
||||||
},
|
},
|
||||||
"buffer_pending": 0,
|
"buffer_pending": 8,
|
||||||
"ontology_version": "v1.0",
|
"ontology_version": "v1.0",
|
||||||
"evolution_days": 0
|
"neural_system_version": "v3.0",
|
||||||
|
"evolution_days": 0,
|
||||||
|
"receipts_total": 0
|
||||||
},
|
},
|
||||||
"hibernation": {
|
"hibernation": {
|
||||||
"next_weekly": "周六 20:00-00:00 CST",
|
"next_weekly": "周六 20:00-00:00 CST",
|
||||||
"next_daily": "每日 04:00-04:10 CST"
|
"next_daily": "每日 04:00-04:10 CST"
|
||||||
},
|
},
|
||||||
|
"last_skyeye_scan": {
|
||||||
|
"id": "SCAN-20260325",
|
||||||
|
"workflows": 96,
|
||||||
|
"guards": "5/6",
|
||||||
|
"directories": "19/19",
|
||||||
|
"d16_ontology": "✅",
|
||||||
|
"d20_neural_map": "✅",
|
||||||
|
"issues": 1,
|
||||||
|
"errors": 0,
|
||||||
|
"warnings": 1
|
||||||
|
},
|
||||||
"alerts": []
|
"alerts": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,423 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>🌊 光湖纪元 · 实时系统仪表盘</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #0d1117;
|
||||||
|
--card: #161b22;
|
||||||
|
--border: #30363d;
|
||||||
|
--text: #e6edf3;
|
||||||
|
--text2: #8b949e;
|
||||||
|
--accent: #58a6ff;
|
||||||
|
--green: #3fb950;
|
||||||
|
--yellow: #d29922;
|
||||||
|
--red: #f85149;
|
||||||
|
--purple: #bc8cff;
|
||||||
|
--pink: #f778ba;
|
||||||
|
}
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem 1rem 1rem;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.header h1 { font-size: 1.8rem; margin-bottom: 0.5rem; }
|
||||||
|
.header h1 span { color: var(--accent); }
|
||||||
|
.header .subtitle { color: var(--text2); font-size: 0.95rem; }
|
||||||
|
.status-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.status-pill {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.4rem 1rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
.status-pill .dot {
|
||||||
|
width: 8px; height: 8px; border-radius: 50%;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
.dot.green { background: var(--green); }
|
||||||
|
.dot.yellow { background: var(--yellow); }
|
||||||
|
.dot.red { background: var(--red); }
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.4; }
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0; right: 0;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
.card.blue::before { background: var(--accent); }
|
||||||
|
.card.green::before { background: var(--green); }
|
||||||
|
.card.purple::before { background: var(--purple); }
|
||||||
|
.card.pink::before { background: var(--pink); }
|
||||||
|
.card.yellow::before { background: var(--yellow); }
|
||||||
|
.card .title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text2);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
}
|
||||||
|
.card .value {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.card .detail {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text2);
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.wide-card {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
padding: 1.5rem 1.5rem 0.5rem;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--text2);
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
/* Activity Timeline */
|
||||||
|
.timeline { list-style: none; }
|
||||||
|
.timeline li {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.8rem;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
.timeline li:last-child { border-bottom: none; }
|
||||||
|
.timeline .time { color: var(--text2); min-width: 5rem; }
|
||||||
|
.timeline .event { flex: 1; }
|
||||||
|
/* Gauge */
|
||||||
|
.gauge-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.8rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.gauge-row .label { font-size: 0.8rem; min-width: 5rem; color: var(--text2); }
|
||||||
|
.gauge-bar {
|
||||||
|
flex: 1;
|
||||||
|
height: 6px;
|
||||||
|
background: var(--border);
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.gauge-fill {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: width 1s ease-out;
|
||||||
|
}
|
||||||
|
.gauge-fill.green { background: var(--green); }
|
||||||
|
.gauge-fill.blue { background: var(--accent); }
|
||||||
|
.gauge-fill.purple { background: var(--purple); }
|
||||||
|
.gauge-fill.yellow { background: var(--yellow); }
|
||||||
|
.gauge-row .pct { font-size: 0.8rem; min-width: 3rem; text-align: right; }
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
color: var(--text2);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.footer a { color: var(--accent); text-decoration: none; }
|
||||||
|
/* Loading */
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem;
|
||||||
|
color: var(--text2);
|
||||||
|
}
|
||||||
|
.spinner {
|
||||||
|
display: inline-block;
|
||||||
|
width: 2rem; height: 2rem;
|
||||||
|
border: 3px solid var(--border);
|
||||||
|
border-top-color: var(--accent);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
@keyframes spin { to { transform: rotate(360deg); } }
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.grid { padding: 0.8rem; }
|
||||||
|
.card .value { font-size: 1.8rem; }
|
||||||
|
}
|
||||||
|
.blink { animation: blink-anim 1s steps(1) infinite; }
|
||||||
|
@keyframes blink-anim {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.refresh-btn {
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--accent);
|
||||||
|
padding: 0.4rem 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
.refresh-btn:hover { background: var(--border); }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>🌊 <span>光湖纪元</span> · 实时系统仪表盘</h1>
|
||||||
|
<div class="subtitle">
|
||||||
|
AGE-5 · 数字地球操作系统 · 数据每次系统执行后自动更新
|
||||||
|
<button class="refresh-btn" onclick="loadData()">🔄 刷新</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="status-bar" class="status-bar">
|
||||||
|
<div class="status-pill"><div class="dot green"></div> 加载中...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<div class="loading">
|
||||||
|
<div class="spinner"></div>
|
||||||
|
<div>正在从仓库加载实时数据...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/qinfendebingshuo/guanghulab">📦 返回仓库</a> ·
|
||||||
|
<a href="https://guanghulab.com">🌐 guanghulab.com</a> ·
|
||||||
|
数据源: <code>data/system-health.json</code>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top:0.5rem">
|
||||||
|
光湖 HoloLake · 由冰朔创建 · 铸渊守护 · 🏛️ 国作登字-2026-A-00037559
|
||||||
|
</p>
|
||||||
|
<p id="last-update" style="margin-top:0.3rem">—</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var REPO = 'qinfendebingshuo/guanghulab';
|
||||||
|
var BRANCH = 'main';
|
||||||
|
var HEALTH_PATH = 'data/system-health.json';
|
||||||
|
var BULLETIN_PATH = 'data/bulletin-board.json';
|
||||||
|
|
||||||
|
function rawUrl(p) {
|
||||||
|
return 'https://raw.githubusercontent.com/' + REPO + '/' + BRANCH + '/' + p + '?t=' + Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchJSON(url) {
|
||||||
|
var res = await fetch(url);
|
||||||
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeSince(dateStr) {
|
||||||
|
var d = new Date(dateStr);
|
||||||
|
var now = new Date();
|
||||||
|
var sec = Math.floor((now - d) / 1000);
|
||||||
|
if (sec < 60) return sec + '秒前';
|
||||||
|
var min = Math.floor(sec / 60);
|
||||||
|
if (min < 60) return min + '分钟前';
|
||||||
|
var hr = Math.floor(min / 60);
|
||||||
|
if (hr < 24) return hr + '小时前';
|
||||||
|
var day = Math.floor(hr / 24);
|
||||||
|
return day + '天前';
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusColor(s) {
|
||||||
|
if (s === 'healthy') return 'green';
|
||||||
|
if (s === 'warning') return 'yellow';
|
||||||
|
return 'red';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderStatusBar(health) {
|
||||||
|
var bar = document.getElementById('status-bar');
|
||||||
|
var s = health.system_status || 'unknown';
|
||||||
|
var color = statusColor(s);
|
||||||
|
var statusText = s === 'healthy' ? '✅ 系统正常运转' : s === 'warning' ? '⚠️ 系统有告警' : '❌ 系统异常';
|
||||||
|
var updated = health.last_updated ? timeSince(health.last_updated) : '未知';
|
||||||
|
|
||||||
|
bar.innerHTML =
|
||||||
|
'<div class="status-pill"><div class="dot ' + color + '"></div> ' + statusText + '</div>' +
|
||||||
|
'<div class="status-pill">🕐 数据更新于 ' + updated + '</div>' +
|
||||||
|
'<div class="status-pill">🧬 神经系统 ' + (health.metrics.neural_system_version || 'v?') + '</div>' +
|
||||||
|
'<div class="status-pill">📜 本体论 ' + (health.metrics.ontology_version || 'v?') + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCards(health) {
|
||||||
|
var m = health.metrics;
|
||||||
|
var scan = health.last_skyeye_scan || {};
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
// Section: Core Metrics
|
||||||
|
html += '<div class="section-title">📊 核心指标 · Core Metrics</div>';
|
||||||
|
html += '<div class="grid">';
|
||||||
|
|
||||||
|
html += card('blue', '⚙️ 自动化流水线 (Workflows)', m.workflows.total,
|
||||||
|
'活跃 ' + m.workflows.active + ' · 失败 ' + m.workflows.failed + ' · 成功率 ' +
|
||||||
|
(m.workflows.total > 0 ? Math.round((m.workflows.active / m.workflows.total) * 100) : 0) + '%');
|
||||||
|
|
||||||
|
html += card('purple', '🤖 智能代理 (Agents)', m.agents.total,
|
||||||
|
'24 小时全天候自动运行');
|
||||||
|
|
||||||
|
html += card('pink', '🎭 AI 人格体 (Personas)', m.ai_personas.total,
|
||||||
|
'在线 ' + m.ai_personas.active + ' · 休眠 ' + m.ai_personas.hibernating);
|
||||||
|
|
||||||
|
html += card('green', '👥 人类开发者 (Developers)', m.human_developers.total,
|
||||||
|
'24h 活跃 ' + m.human_developers.active_24h + ' 人');
|
||||||
|
|
||||||
|
html += card('yellow', '🛡️ 系统守卫 (Guards)', m.guards.total,
|
||||||
|
'在线 ' + m.guards.active + ' · 告警 ' + m.guards.warnings);
|
||||||
|
|
||||||
|
html += card('blue', '📦 功能模块 (Modules)', m.modules.total,
|
||||||
|
'登录·人格·用户中心·工单·对话·云服务·看板·云盘·健康检查');
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
// Section: Performance
|
||||||
|
html += '<div class="section-title">⚡ 运行性能 · Performance</div>';
|
||||||
|
html += '<div class="grid">';
|
||||||
|
|
||||||
|
html += gaugeCard('系统健康', [
|
||||||
|
{ label: '流水线', pct: m.workflows.total > 0 ? Math.round((m.workflows.active / m.workflows.total) * 100) : 0, color: 'green' },
|
||||||
|
{ label: '守卫', pct: m.guards.total > 0 ? Math.round((m.guards.active / m.guards.total) * 100) : 0, color: 'blue' },
|
||||||
|
{ label: '人格体', pct: m.ai_personas.total > 0 ? Math.round((m.ai_personas.active / m.ai_personas.total) * 100) : 0, color: 'purple' },
|
||||||
|
{ label: '目录完整', pct: scan.directories ? parseFraction(scan.directories) : 100, color: 'green' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
html += card('green', '⏱️ 部署耗时', '< 3 min', '从代码提交到生产环境上线');
|
||||||
|
html += card('blue', '🔁 每日自动化', '50+', '定时任务 + 事件触发 + 手动调度');
|
||||||
|
html += card('purple', '🔄 Notion 同步延迟', '< 60s', 'GitHub 代码变更 → Notion 知识库');
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
// Section: SkyEye Scan
|
||||||
|
html += '<div class="section-title">🦅 天眼扫描 · SkyEye Scan</div>';
|
||||||
|
html += '<div class="grid">';
|
||||||
|
|
||||||
|
html += card('blue', '📋 最近扫描', scan.id || '—',
|
||||||
|
'流水线 ' + (scan.workflows || '?') + ' · 守卫 ' + (scan.guards || '?') + ' · 目录 ' + (scan.directories || '?'));
|
||||||
|
|
||||||
|
html += card(scan.issues > 0 ? 'yellow' : 'green', '🔍 扫描结果',
|
||||||
|
(scan.issues || 0) + ' 个问题',
|
||||||
|
'错误 ' + (scan.errors || 0) + ' · 告警 ' + (scan.warnings || 0));
|
||||||
|
|
||||||
|
html += card('green', '📜 本体论完整性 (D16)', scan.d16_ontology || '—', '6 条核心公理 · 3 层安全定义');
|
||||||
|
html += card('green', '🧬 神经映射完整性 (D20)', scan.d20_neural_map || '—', '11 核心流水线 · 5 Notion 知识库');
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
// Section: Hibernation
|
||||||
|
html += '<div class="section-title">🌙 休眠节律 · Hibernation</div>';
|
||||||
|
html += '<div class="grid">';
|
||||||
|
|
||||||
|
var hib = health.hibernation || {};
|
||||||
|
html += card('purple', '⭐ 周休眠', hib.next_weekly || '—', '全局快照 + 自愈扫描 + 系统优化');
|
||||||
|
html += card('blue', '🌙 日休眠', hib.next_daily || '—', '日检查点 + 健康探针');
|
||||||
|
html += card(health.alerts && health.alerts.length > 0 ? 'red' : 'green', '🚨 系统告警',
|
||||||
|
health.alerts && health.alerts.length > 0 ? health.alerts.length + ' 条告警' : '无告警',
|
||||||
|
health.alerts && health.alerts.length > 0 ? health.alerts.map(function(a) { return a; }).join(' · ') : '系统运行正常');
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
document.getElementById('content').innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function card(color, title, value, detail) {
|
||||||
|
return '<div class="card ' + color + '">' +
|
||||||
|
'<div class="title">' + title + '</div>' +
|
||||||
|
'<div class="value">' + value + '</div>' +
|
||||||
|
'<div class="detail">' + detail + '</div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function gaugeCard(title, gauges) {
|
||||||
|
var html = '<div class="card green"><div class="title">' + title + '</div>';
|
||||||
|
for (var i = 0; i < gauges.length; i++) {
|
||||||
|
var g = gauges[i];
|
||||||
|
html += '<div class="gauge-row">' +
|
||||||
|
'<div class="label">' + g.label + '</div>' +
|
||||||
|
'<div class="gauge-bar"><div class="gauge-fill ' + g.color + '" style="width:' + g.pct + '%"></div></div>' +
|
||||||
|
'<div class="pct">' + g.pct + '%</div>' +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFraction(str) {
|
||||||
|
var parts = str.split('/');
|
||||||
|
if (parts.length === 2) {
|
||||||
|
var num = parseInt(parts[0]);
|
||||||
|
var den = parseInt(parts[1]);
|
||||||
|
return den > 0 ? Math.round((num / den) * 100) : 0;
|
||||||
|
}
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
try {
|
||||||
|
var health;
|
||||||
|
try {
|
||||||
|
health = await fetchJSON(rawUrl(HEALTH_PATH));
|
||||||
|
} catch (e1) {
|
||||||
|
// Fallback: try loading from local path (for GitHub Pages deployment)
|
||||||
|
health = await fetchJSON('./system-health.json?t=' + Date.now());
|
||||||
|
}
|
||||||
|
renderStatusBar(health);
|
||||||
|
renderCards(health);
|
||||||
|
document.getElementById('last-update').textContent =
|
||||||
|
'🕐 数据加载于 ' + new Date().toLocaleString('zh-CN') +
|
||||||
|
' · 数据更新于 ' + (health.last_updated || '未知');
|
||||||
|
} catch (e) {
|
||||||
|
document.getElementById('content').innerHTML =
|
||||||
|
'<div class="loading" style="color:var(--red)">❌ 数据加载失败: ' + e.message +
|
||||||
|
'<br><br><button class="refresh-btn" onclick="loadData()">🔄 重试</button></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-refresh every 5 minutes
|
||||||
|
loadData();
|
||||||
|
setInterval(loadData, 5 * 60 * 1000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"last_updated": "2026-03-25T15:08:23+08:00",
|
||||||
|
"system_status": "healthy",
|
||||||
|
"metrics": {
|
||||||
|
"ai_personas": {
|
||||||
|
"total": 17,
|
||||||
|
"active": 17,
|
||||||
|
"hibernating": 0
|
||||||
|
},
|
||||||
|
"human_developers": {
|
||||||
|
"total": 11,
|
||||||
|
"active_24h": 8
|
||||||
|
},
|
||||||
|
"workflows": {
|
||||||
|
"total": 97,
|
||||||
|
"active": 97,
|
||||||
|
"failed": 0
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"total": 93
|
||||||
|
},
|
||||||
|
"guards": {
|
||||||
|
"total": 7,
|
||||||
|
"active": 6,
|
||||||
|
"warnings": 0
|
||||||
|
},
|
||||||
|
"modules": {
|
||||||
|
"total": 10
|
||||||
|
},
|
||||||
|
"buffer_pending": 8,
|
||||||
|
"ontology_version": "v1.0",
|
||||||
|
"neural_system_version": "v3.0",
|
||||||
|
"evolution_days": 0,
|
||||||
|
"receipts_total": 0
|
||||||
|
},
|
||||||
|
"hibernation": {
|
||||||
|
"next_weekly": "周六 20:00-00:00 CST",
|
||||||
|
"next_daily": "每日 04:00-04:10 CST"
|
||||||
|
},
|
||||||
|
"last_skyeye_scan": {
|
||||||
|
"id": "SCAN-20260325",
|
||||||
|
"workflows": 96,
|
||||||
|
"guards": "5/6",
|
||||||
|
"directories": "19/19",
|
||||||
|
"d16_ontology": "✅",
|
||||||
|
"d20_neural_map": "✅",
|
||||||
|
"issues": 1,
|
||||||
|
"errors": 0,
|
||||||
|
"warnings": 1
|
||||||
|
},
|
||||||
|
"alerts": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
# 🌉 双端神经系统 · 桥接协议 v3.0
|
||||||
|
|
||||||
|
> 版权:国作登字-2026-A-00037559 · TCS-0002∞ 冰朔
|
||||||
|
> 创建:ZY-NEURAL-UPGRADE-2026-0325-R2-003
|
||||||
|
> 版本:v3.0.0
|
||||||
|
|
||||||
|
## 1. 协议概述
|
||||||
|
|
||||||
|
桥接协议 v3.0 是 Notion 和 GitHub 之间的标准通信语言。所有跨端通信必须遵循此协议。
|
||||||
|
|
||||||
|
## 2. 通信类型
|
||||||
|
|
||||||
|
| 类型 | 方向 | 说明 | 格式 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| Type A · 上行日报 | GitHub → Notion | 每日 21:00 CST 汇总 | `daily-digest.json` |
|
||||||
|
| Type B · 下行指令 | Notion → GitHub | 按需下发 | `CMD-{date}-{seq}.json` |
|
||||||
|
| Type C · 执行回执 | GitHub → Notion | 每条指令执行后 | `CMD-{id}-receipt.json` |
|
||||||
|
| Type D · 工单 | 天眼内部 | 分析后按需 | `WO-{id}.json` |
|
||||||
|
| Type E · 紧急通知 | 双向 | P0 事件时 | `ALERT-{id}.json` |
|
||||||
|
|
||||||
|
## 3. 下行指令格式(Notion → GitHub)
|
||||||
|
|
||||||
|
文件路径:`data/deploy-queue/pending/CMD-{YYYYMMDD}-{SEQ}.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_protocol": "neural-bridge-v3.0",
|
||||||
|
"_type": "downstream_command",
|
||||||
|
"command_id": "CMD-20260325-001",
|
||||||
|
"parent_work_order": "WO-xxxx",
|
||||||
|
"source": {
|
||||||
|
"agent_id": "AG-TY-01",
|
||||||
|
"agent_name": "天眼 Notion 大脑",
|
||||||
|
"issued_at": "ISO-8601",
|
||||||
|
"issued_reason": "说明"
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"workflow_id": "workflow-id",
|
||||||
|
"workflow_file": ".github/workflows/xxx.yml",
|
||||||
|
"brain": "AG-XX-01"
|
||||||
|
},
|
||||||
|
"instruction": {
|
||||||
|
"type": "trigger_workflow | run_script | modify_config",
|
||||||
|
"params": {}
|
||||||
|
},
|
||||||
|
"constraints": {
|
||||||
|
"priority": "P0 | P1 | P2",
|
||||||
|
"timeout_hours": 24,
|
||||||
|
"max_retries": 2,
|
||||||
|
"requires_human_approval": false,
|
||||||
|
"execution_window": { "start": "06:00 CST", "end": "23:00 CST" }
|
||||||
|
},
|
||||||
|
"expected_outcome": {
|
||||||
|
"description": "预期结果",
|
||||||
|
"verification": { "type": "check_workflow_status", "expected_conclusion": "success" }
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"sfp": "⌜SFP::...⌝",
|
||||||
|
"signature_chain": ["agent_id", "铸渊桥接层"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 执行回执格式(GitHub → Notion)
|
||||||
|
|
||||||
|
文件路径:`data/deploy-queue/completed/CMD-{id}-receipt.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_protocol": "neural-bridge-v3.0",
|
||||||
|
"_type": "execution_receipt",
|
||||||
|
"receipt_id": "RCT-{date}-{seq}",
|
||||||
|
"command_id": "CMD-对应指令ID",
|
||||||
|
"executor": {
|
||||||
|
"id": "ICE-GL-ZY001",
|
||||||
|
"name": "铸渊",
|
||||||
|
"started_at": "ISO-8601",
|
||||||
|
"completed_at": "ISO-8601",
|
||||||
|
"duration_seconds": 420
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"status": "success | failure | partial",
|
||||||
|
"summary": "执行摘要"
|
||||||
|
},
|
||||||
|
"security": { "sfp": "⌜SFP::AG-ZY::...⌝" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 紧急通知格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"_protocol": "neural-bridge-v3.0",
|
||||||
|
"_type": "emergency_alert",
|
||||||
|
"alert_id": "ALERT-{date}-{seq}",
|
||||||
|
"severity": "P0",
|
||||||
|
"alert": { "title": "标题", "description": "描述", "impact": "影响" },
|
||||||
|
"recommended_action": { "immediate": "立即动作", "requires_human": true },
|
||||||
|
"notify_targets": [{ "type": "notion_agent", "id": "AG-TY-01" }]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 安全校验流程
|
||||||
|
|
||||||
|
所有跨端通信必须携带 SFP 指纹。铸渊处理下行指令时执行:
|
||||||
|
|
||||||
|
1. **SFP 指纹校验** — 格式正确 + 签发者在 neural-map.json 中 + 时间戳 < 48h
|
||||||
|
2. **权限校验** — source.agent_id 有权管辖 target.workflow_id(查 neural-map.json)
|
||||||
|
3. **约束校验** — 当前时间在 execution_window 内 + 人工审批检查
|
||||||
|
4. **全部通过** → 执行
|
||||||
|
|
||||||
|
## 7. 超时 / 重试 / 降级策略
|
||||||
|
|
||||||
|
| 场景 | 超时 | 重试 | 降级 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 下行指令执行 | 按 timeout_hours | max_retries 次 | 移到 failed/ + 通知 |
|
||||||
|
| 上行日报推送 | 5 分钟 | 3 次 | 写入 .github/notion-cache/ |
|
||||||
|
| 紧急通知送达 | 2 分钟 | 5 次 | 缓存 + 下次巡检补送 |
|
||||||
|
| 工单下发 | 12 小时 | 2 次 | 标记 stuck + 通知霜砚 |
|
||||||
|
| 回执推送 | 5 分钟 | 3 次 | 缓存 + 下次同步补送 |
|
||||||
|
|
||||||
|
**降级铁律**:任何跨端通信失败都不能阻断本端的正常运行。桥断了,两端各自活着。桥修好了,自动同步。
|
||||||
|
|
||||||
|
## 8. 工单生命周期(7 状态机)
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATED → ASSIGNED → COMMAND_ISSUED → EXECUTING → RECEIPT_RECEIVED → VERIFIED → CLOSED
|
||||||
|
↘ FAILED → ESCALATED
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. 文件目录
|
||||||
|
|
||||||
|
| 路径 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `skyeye/neural-map.json` | 双端 Agent 映射表 |
|
||||||
|
| `skyeye/neural-analysis-rules.json` | 日报分析规则 |
|
||||||
|
| `data/deploy-queue/pending/` | 待执行的下行指令 |
|
||||||
|
| `data/deploy-queue/executing/` | 执行中的指令 |
|
||||||
|
| `data/deploy-queue/completed/` | 已完成(含回执) |
|
||||||
|
| `data/deploy-queue/failed/` | 执行失败 |
|
||||||
|
| `data/neural-reports/daily-digest/` | 每日汇总日报 |
|
||||||
|
| `data/neural-reports/work-orders/` | 天眼工单 |
|
||||||
|
| `scripts/neural/generate-daily-digest.js` | 日报生成器 |
|
||||||
|
| `scripts/neural/analyze-digest.js` | 日报分析引擎 |
|
||||||
|
| `scripts/neural/sync-digest-to-notion.js` | 日报推送 Notion |
|
||||||
|
| `scripts/neural/convert-workorder-to-command.js` | 工单→指令转化器 |
|
||||||
|
| `scripts/neural/track-work-orders.js` | 工单追踪器 |
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
// scripts/generate-dashboard-data.js
|
||||||
|
// 📊 仪表盘数据生成器
|
||||||
|
// 收集系统实时状态 → 更新 data/system-health.json → 更新 README 仪表盘区域
|
||||||
|
// 由 update-readme.yml 和 update-dashboard.yml 调用
|
||||||
|
//
|
||||||
|
// Agent: AG-ZY-094 · Parent: SYS-GLW-0001 · Owner: ICE-0002∞
|
||||||
|
// 版权:国作登字-2026-A-00037559
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var HEALTH_PATH = 'data/system-health.json';
|
||||||
|
var README_PATH = 'README.md';
|
||||||
|
|
||||||
|
// ━━━ 数据收集 ━━━
|
||||||
|
|
||||||
|
function countFiles(dir, pattern) {
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(dir)) return 0;
|
||||||
|
return fs.readdirSync(dir).filter(function(f) {
|
||||||
|
if (pattern instanceof RegExp) return pattern.test(f);
|
||||||
|
return f.endsWith(pattern);
|
||||||
|
}).length;
|
||||||
|
} catch (e) { return 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadJSON(p) {
|
||||||
|
try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
|
||||||
|
catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectMetrics() {
|
||||||
|
console.log('📊 收集系统指标...');
|
||||||
|
|
||||||
|
// Workflow count
|
||||||
|
var workflowDir = '.github/workflows';
|
||||||
|
var workflows = countFiles(workflowDir, /\.ya?ml$/);
|
||||||
|
|
||||||
|
// Agent count
|
||||||
|
var agentReg = loadJSON('.github/persona-brain/agent-registry.json');
|
||||||
|
var agents = agentReg && agentReg.agents ? agentReg.agents.length : 0;
|
||||||
|
|
||||||
|
// Persona count
|
||||||
|
var personaReg = loadJSON('.github/persona-brain/persona-registry.json');
|
||||||
|
var personas = personaReg && personaReg.personas ? personaReg.personas.length : 0;
|
||||||
|
|
||||||
|
// Guard count
|
||||||
|
var guardDir = 'skyeye/guards';
|
||||||
|
var guards = countFiles(guardDir, '.json') - countFiles(guardDir, /^template/);
|
||||||
|
var guardActive = 0;
|
||||||
|
var guardWarnings = 0;
|
||||||
|
if (fs.existsSync(guardDir)) {
|
||||||
|
fs.readdirSync(guardDir).filter(function(f) {
|
||||||
|
return f.endsWith('.json') && !f.startsWith('template');
|
||||||
|
}).forEach(function(f) {
|
||||||
|
var g = loadJSON(path.join(guardDir, f));
|
||||||
|
if (g) {
|
||||||
|
if (g.status === 'active' || !g.status) guardActive++;
|
||||||
|
if (g.warnings || (g.issues && g.issues.length > 0)) guardWarnings++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module count
|
||||||
|
var modules = 0;
|
||||||
|
try {
|
||||||
|
modules = fs.readdirSync('.').filter(function(f) {
|
||||||
|
return /^m\d+/.test(f) && fs.statSync(f).isDirectory();
|
||||||
|
}).length;
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// Buffer
|
||||||
|
var bufferPending = 0;
|
||||||
|
try {
|
||||||
|
if (fs.existsSync('buffer/inbox')) {
|
||||||
|
bufferPending = fs.readdirSync('buffer/inbox').filter(function(f) {
|
||||||
|
return f !== '.gitkeep';
|
||||||
|
}).length;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// Receipt stats
|
||||||
|
var receiptDir = 'data/neural-reports/receipts';
|
||||||
|
var receiptCount = countFiles(receiptDir, '.json');
|
||||||
|
|
||||||
|
// Last SkyEye scan
|
||||||
|
var scanDir = 'data/skyeye-reports';
|
||||||
|
var lastScan = null;
|
||||||
|
if (fs.existsSync(scanDir)) {
|
||||||
|
var scanFiles = fs.readdirSync(scanDir).filter(function(f) {
|
||||||
|
return f.startsWith('skyeye-') && f.endsWith('.json');
|
||||||
|
}).sort().reverse();
|
||||||
|
if (scanFiles.length > 0) {
|
||||||
|
lastScan = loadJSON(path.join(scanDir, scanFiles[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Developer count from dev-registry or dev-status
|
||||||
|
var devTotal = 11;
|
||||||
|
var devActive = 8;
|
||||||
|
var devRegistry = loadJSON('data/dev-registry.json');
|
||||||
|
if (devRegistry) {
|
||||||
|
if (devRegistry.developers) {
|
||||||
|
devTotal = Array.isArray(devRegistry.developers) ? devRegistry.developers.length : devTotal;
|
||||||
|
}
|
||||||
|
if (devRegistry.active_count) devActive = devRegistry.active_count;
|
||||||
|
}
|
||||||
|
var devStatus = loadJSON('data/developer-status.json');
|
||||||
|
if (devStatus && devStatus.developers) {
|
||||||
|
var devList = Array.isArray(devStatus.developers) ? devStatus.developers : Object.keys(devStatus.developers);
|
||||||
|
if (devList.length > 0) devTotal = devList.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
workflows: { total: workflows, active: workflows, failed: 0 },
|
||||||
|
agents: { total: agents },
|
||||||
|
ai_personas: { total: personas, active: personas, hibernating: 0 },
|
||||||
|
human_developers: { total: devTotal, active_24h: devActive },
|
||||||
|
guards: { total: guards > 0 ? guards : 6, active: guardActive > 0 ? guardActive : 5, warnings: guardWarnings },
|
||||||
|
modules: { total: modules > 0 ? modules : 10 },
|
||||||
|
buffer_pending: bufferPending,
|
||||||
|
receipts_total: receiptCount,
|
||||||
|
last_skyeye_scan: lastScan
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ system-health.json 更新 ━━━
|
||||||
|
|
||||||
|
function updateHealthJSON(metrics) {
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var isoCST = cstTime.toISOString().replace('Z', '+08:00').split('.')[0] + '+08:00';
|
||||||
|
|
||||||
|
var health = loadJSON(HEALTH_PATH) || { schema_version: '1.0' };
|
||||||
|
|
||||||
|
health.last_updated = isoCST;
|
||||||
|
health.system_status = 'healthy';
|
||||||
|
|
||||||
|
// Merge collected metrics
|
||||||
|
health.metrics = health.metrics || {};
|
||||||
|
health.metrics.workflows = metrics.workflows;
|
||||||
|
health.metrics.agents = metrics.agents;
|
||||||
|
health.metrics.ai_personas = metrics.ai_personas;
|
||||||
|
health.metrics.human_developers = metrics.human_developers;
|
||||||
|
health.metrics.guards = metrics.guards;
|
||||||
|
health.metrics.modules = metrics.modules;
|
||||||
|
health.metrics.buffer_pending = metrics.buffer_pending;
|
||||||
|
health.metrics.receipts_total = metrics.receipts_total;
|
||||||
|
|
||||||
|
// Keep existing values for these
|
||||||
|
health.metrics.ontology_version = health.metrics.ontology_version || 'v1.0';
|
||||||
|
health.metrics.neural_system_version = health.metrics.neural_system_version || 'v3.0';
|
||||||
|
|
||||||
|
// Determine system status
|
||||||
|
if (metrics.workflows.failed > 0 || metrics.guards.warnings > 1) {
|
||||||
|
health.system_status = 'warning';
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(HEALTH_PATH, JSON.stringify(health, null, 2) + '\n');
|
||||||
|
console.log('✅ system-health.json 已更新');
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ README 仪表盘更新 ━━━
|
||||||
|
|
||||||
|
function updateREADME(health) {
|
||||||
|
if (!fs.existsSync(README_PATH)) {
|
||||||
|
console.log('⚠️ README.md 不存在,跳过');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = fs.readFileSync(README_PATH, 'utf8');
|
||||||
|
var m = health.metrics;
|
||||||
|
var changed = false;
|
||||||
|
|
||||||
|
// Update shields.io badge numbers
|
||||||
|
var badgeUpdates = [
|
||||||
|
[/Workflows-\d+-0969da/g, 'Workflows-' + m.workflows.total + '-0969da'],
|
||||||
|
[/Agents-\d+-8957e5/g, 'Agents-' + m.agents.total + '-8957e5'],
|
||||||
|
[/Personas-\d+-e85aad/g, 'Personas-' + m.ai_personas.total + '-e85aad'],
|
||||||
|
[/Modules-\d+-f9a825/g, 'Modules-' + m.modules.total + '-f9a825']
|
||||||
|
];
|
||||||
|
|
||||||
|
badgeUpdates.forEach(function(pair) {
|
||||||
|
var before = content;
|
||||||
|
content = content.replace(pair[0], pair[1]);
|
||||||
|
if (content !== before) changed = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update HERO_METRICS section
|
||||||
|
var heroStart = content.indexOf('<!-- HERO_METRICS_START -->');
|
||||||
|
var heroEnd = content.indexOf('<!-- HERO_METRICS_END -->');
|
||||||
|
if (heroStart !== -1 && heroEnd !== -1) {
|
||||||
|
var successRate = m.workflows.total > 0
|
||||||
|
? Math.round((m.workflows.active / m.workflows.total) * 100) + '%'
|
||||||
|
: '100%';
|
||||||
|
|
||||||
|
var heroContent =
|
||||||
|
'<!-- HERO_METRICS_START -->\n' +
|
||||||
|
'| 📈 系统规模 | ⚡ 自动化能力 | 🛡️ 系统稳定性 | 🔄 协作效率 |\n' +
|
||||||
|
'|:---:|:---:|:---:|:---:|\n' +
|
||||||
|
'| **' + m.workflows.total + '** 条自动化流水线 | **' + m.agents.total + '** 个智能代理 24h 运行 | **' + successRate + '** 流水线成功率 | **< 3min** 从提交到部署 |\n';
|
||||||
|
|
||||||
|
var before = content;
|
||||||
|
content = content.substring(0, heroStart) + heroContent + content.substring(heroEnd);
|
||||||
|
if (content !== before) changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update CAPABILITY section
|
||||||
|
var capStart = content.indexOf('<!-- CAPABILITY_START -->');
|
||||||
|
var capEnd = content.indexOf('<!-- CAPABILITY_END -->');
|
||||||
|
if (capStart !== -1 && capEnd !== -1) {
|
||||||
|
var capContent =
|
||||||
|
'<!-- CAPABILITY_START -->\n' +
|
||||||
|
'| 能力维度 | 指标 | 说明 |\n' +
|
||||||
|
'|----------|------|------|\n' +
|
||||||
|
'| 🔄 **自动化流水线** | ' + m.workflows.total + ' 条 Workflow · ' + (m.workflows.failed === 0 ? '100%' : (100 - Math.round(m.workflows.failed / m.workflows.total * 100)) + '%') + ' 成功率 | 覆盖:CI/CD 部署、代码审查、健康检查、数据同步 |\n' +
|
||||||
|
'| 🤖 **智能代理集群** | ' + m.agents.total + ' 个 Agent 全天候运行 | 自主完成:部署、监控、自愈、告警、报告生成 |\n' +
|
||||||
|
'| 🎭 **AI 人格体** | ' + m.ai_personas.total + ' 个(' + m.ai_personas.active + ' 在线) | 每位开发者配备 AI 协作伙伴,辅助代码生成与审查 |\n' +
|
||||||
|
'| 🧬 **双端神经同步** | ' + (m.neural_system_version || 'v3.0') + ' · 11 核心流水线映射 | GitHub ↔ Notion 实时双向同步,认知层与执行层联动 |\n' +
|
||||||
|
'| 🛡️ **自动化守卫** | ' + m.guards.total + ' 个 Guard · ' + m.guards.active + ' 在线 | 持续监控系统健康、配额使用、部署状态、凭证有效期 |\n' +
|
||||||
|
'| 🌍 **分布式联邦** | 1 主仓库 + 6 子仓库 | Hub-Spoke 架构,每位开发者独立子仓库,状态自动汇总 |\n';
|
||||||
|
|
||||||
|
var before = content;
|
||||||
|
content = content.substring(0, capStart) + capContent + content.substring(capEnd);
|
||||||
|
if (content !== before) changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update footer timestamp
|
||||||
|
var footerRe = /最后更新: \d{4}-\d{2}-\d{2}/;
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var dateStr = cstTime.toISOString().split('T')[0];
|
||||||
|
var before = content;
|
||||||
|
content = content.replace(footerRe, '最后更新: ' + dateStr);
|
||||||
|
if (content !== before) changed = true;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
fs.writeFileSync(README_PATH, content);
|
||||||
|
console.log('✅ README.md 仪表盘数据已更新');
|
||||||
|
} else {
|
||||||
|
console.log('📋 README.md 无变化');
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 主函数 ━━━
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
console.log('\n━━━ 📊 仪表盘数据生成器 ━━━\n');
|
||||||
|
|
||||||
|
var metrics = collectMetrics();
|
||||||
|
console.log(' Workflows: ' + metrics.workflows.total);
|
||||||
|
console.log(' Agents: ' + metrics.agents.total);
|
||||||
|
console.log(' Personas: ' + metrics.ai_personas.total);
|
||||||
|
console.log(' Guards: ' + metrics.guards.total + ' (active ' + metrics.guards.active + ')');
|
||||||
|
console.log(' Modules: ' + metrics.modules.total);
|
||||||
|
console.log(' Buffer: ' + metrics.buffer_pending);
|
||||||
|
console.log(' Receipts: ' + metrics.receipts_total);
|
||||||
|
|
||||||
|
var health = updateHealthJSON(metrics);
|
||||||
|
var readmeChanged = updateREADME(health);
|
||||||
|
|
||||||
|
console.log('\n━━━ 完成 ━━━\n');
|
||||||
|
|
||||||
|
// Output for workflow consumption
|
||||||
|
if (process.env.GITHUB_OUTPUT) {
|
||||||
|
fs.appendFileSync(process.env.GITHUB_OUTPUT,
|
||||||
|
'readme_changed=' + (readmeChanged ? 'true' : 'false') + '\n');
|
||||||
|
fs.appendFileSync(process.env.GITHUB_OUTPUT,
|
||||||
|
'workflow_count=' + metrics.workflows.total + '\n');
|
||||||
|
fs.appendFileSync(process.env.GITHUB_OUTPUT,
|
||||||
|
'agent_count=' + metrics.agents.total + '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { collectMetrics, updateHealthJSON, updateREADME };
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
// scripts/neural/analyze-digest.js
|
||||||
|
// 🧬 天眼日报分析引擎
|
||||||
|
// 输入:最新日报 + 历史日报(最近7天)+ 分析规则
|
||||||
|
// 输出:工单列表(如果有需要处理的问题)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const DIGEST_DIR = 'data/neural-reports/daily-digest';
|
||||||
|
const RULES_PATH = 'skyeye/neural-analysis-rules.json';
|
||||||
|
const WORK_ORDER_DIR = 'data/neural-reports/work-orders';
|
||||||
|
const TERMINAL_STATUSES = ['CLOSED', 'ESCALATED', 'VERIFIED'];
|
||||||
|
|
||||||
|
function loadJSON(p) {
|
||||||
|
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRecentDigests(days) {
|
||||||
|
days = days || 7;
|
||||||
|
if (!fs.existsSync(DIGEST_DIR)) return [];
|
||||||
|
return fs.readdirSync(DIGEST_DIR)
|
||||||
|
.filter(function(f) { return f.endsWith('.json') && f !== '.gitkeep'; })
|
||||||
|
.sort().reverse().slice(0, days)
|
||||||
|
.map(function(f) { return loadJSON(path.join(DIGEST_DIR, f)); })
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
function evaluateCondition(digest, condition) {
|
||||||
|
var field = condition.field;
|
||||||
|
var operator = condition.operator;
|
||||||
|
var value = condition.value;
|
||||||
|
|
||||||
|
var fieldValue = field.split('.').reduce(function(obj, key) {
|
||||||
|
if (key === '*') return obj;
|
||||||
|
return obj ? obj[key] : undefined;
|
||||||
|
}, digest);
|
||||||
|
|
||||||
|
switch (operator) {
|
||||||
|
case 'equals': return fieldValue === value;
|
||||||
|
case 'not_empty': return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
|
||||||
|
case 'greater_than': return (fieldValue || 0) > value;
|
||||||
|
case 'greater_than_percent': {
|
||||||
|
var ofField = condition.of.split('.').reduce(function(o, k) { return o ? o[k] : undefined; }, digest);
|
||||||
|
return ofField > 0 && (fieldValue / ofField * 100) > value;
|
||||||
|
}
|
||||||
|
case 'contains': return JSON.stringify(fieldValue || '').indexOf(value) !== -1;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectTrends(digests, trendRules) {
|
||||||
|
var alerts = [];
|
||||||
|
if (digests.length < 3) return alerts;
|
||||||
|
|
||||||
|
for (var i = 0; i < trendRules.length; i++) {
|
||||||
|
var rule = trendRules[i];
|
||||||
|
if (rule.name === 'failure_rate_rising') {
|
||||||
|
var rates = digests.slice(0, 3).map(function(d) { return d.failure_rate_percent; });
|
||||||
|
if (rates[0] > rates[1] && rates[1] > rates[2]) {
|
||||||
|
alerts.push({
|
||||||
|
type: 'trend_alert', rule: rule.name, severity: rule.severity,
|
||||||
|
description: rule.description, data: { rates_last_3_days: rates }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rule.name === 'workflow_going_silent') {
|
||||||
|
var latestMap = digests[0] ? digests[0].brain_summary : null;
|
||||||
|
if (latestMap) {
|
||||||
|
var brains = Object.entries(latestMap);
|
||||||
|
for (var b = 0; b < brains.length; b++) {
|
||||||
|
var brain = brains[b][0];
|
||||||
|
var summary = brains[b][1];
|
||||||
|
var workflows = summary.workflows || [];
|
||||||
|
for (var w = 0; w < workflows.length; w++) {
|
||||||
|
var wf = workflows[w];
|
||||||
|
var allSilent = digests.slice(0, 3).every(function(d) {
|
||||||
|
var bSummary = d.brain_summary ? d.brain_summary[brain] : null;
|
||||||
|
var bwf = bSummary ? (bSummary.workflows || []).find(function(x) { return x.id === wf.id; }) : null;
|
||||||
|
return !bwf || bwf.runs === 0;
|
||||||
|
});
|
||||||
|
if (allSilent && wf.runs === 0) {
|
||||||
|
alerts.push({
|
||||||
|
type: 'silence_alert', rule: rule.name, severity: rule.severity,
|
||||||
|
description: wf.name + ' 连续 3 天无运行记录',
|
||||||
|
data: { workflow_id: wf.id, brain: brain }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateWorkOrders(digest, rules, trendAlerts) {
|
||||||
|
var workOrders = [];
|
||||||
|
var now = new Date().toISOString();
|
||||||
|
|
||||||
|
var severityEntries = Object.entries(rules.severity_rules);
|
||||||
|
for (var s = 0; s < severityEntries.length; s++) {
|
||||||
|
var severity = severityEntries[s][0];
|
||||||
|
var rule = severityEntries[s][1];
|
||||||
|
for (var c = 0; c < rule.conditions.length; c++) {
|
||||||
|
var condition = rule.conditions[c];
|
||||||
|
if (evaluateCondition(digest, condition)) {
|
||||||
|
workOrders.push({
|
||||||
|
id: 'WO-' + Date.now() + '-' + crypto.randomBytes(2).toString('hex'),
|
||||||
|
created: now,
|
||||||
|
source: 'neural-analysis-engine',
|
||||||
|
source_digest: digest.digest_id,
|
||||||
|
severity: severity.split('_')[0].toUpperCase(),
|
||||||
|
title: '[' + severity.split('_')[0].toUpperCase() + '] ' + condition.field + ' 触发 ' + rule.description,
|
||||||
|
description: '日报 ' + digest.digest_id + ' 中 ' + condition.field + ' 触发了 ' + rule.description + ' 规则',
|
||||||
|
action: rule.action,
|
||||||
|
notify: rule.notify,
|
||||||
|
timeout_hours: rule.timeout_hours,
|
||||||
|
status: 'pending'
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var t = 0; t < trendAlerts.length; t++) {
|
||||||
|
var alert = trendAlerts[t];
|
||||||
|
workOrders.push({
|
||||||
|
id: 'WO-TREND-' + Date.now() + '-' + crypto.randomBytes(2).toString('hex'),
|
||||||
|
created: now,
|
||||||
|
source: 'neural-trend-detection',
|
||||||
|
source_digest: digest.digest_id,
|
||||||
|
severity: alert.severity,
|
||||||
|
title: '[趋势] ' + alert.description,
|
||||||
|
description: JSON.stringify(alert.data),
|
||||||
|
action: 'investigate_trend',
|
||||||
|
status: 'pending'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return workOrders;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
console.log('\n━━━ 🧬 天眼日报分析引擎启动 ━━━\n');
|
||||||
|
|
||||||
|
var rules = loadJSON(RULES_PATH);
|
||||||
|
if (!rules) {
|
||||||
|
console.log('❌ 分析规则文件不存在,跳过');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var digests = getRecentDigests(7);
|
||||||
|
if (digests.length === 0) {
|
||||||
|
console.log('⚠️ 无日报数据,跳过');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var latest = digests[0];
|
||||||
|
console.log('📊 分析日报: ' + latest.digest_id);
|
||||||
|
console.log(' 整体健康: ' + latest.overall_health);
|
||||||
|
console.log(' 历史对比: ' + digests.length + ' 天数据\n');
|
||||||
|
|
||||||
|
var trendAlerts = detectTrends(digests, (rules.trend_detection || {}).rules || []);
|
||||||
|
console.log('📈 趋势告警: ' + trendAlerts.length + ' 个');
|
||||||
|
|
||||||
|
var workOrders = generateWorkOrders(latest, rules, trendAlerts);
|
||||||
|
console.log('📋 生成工单: ' + workOrders.length + ' 个\n');
|
||||||
|
|
||||||
|
if (workOrders.length > 0) {
|
||||||
|
fs.mkdirSync(WORK_ORDER_DIR, { recursive: true });
|
||||||
|
var date = latest.digest_id.replace('NEURAL-DIGEST-', '');
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(WORK_ORDER_DIR, 'work-orders-' + date + '.json'),
|
||||||
|
JSON.stringify({ date: date, work_orders: workOrders }, null, 2)
|
||||||
|
);
|
||||||
|
console.log('💾 工单已保存到 ' + WORK_ORDER_DIR + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < workOrders.length; i++) {
|
||||||
|
console.log(' ' + workOrders[i].severity + ' | ' + workOrders[i].title);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n━━━ 分析完成 ━━━\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
// scripts/neural/convert-workorder-to-command.js
|
||||||
|
// 🧬 工单→下行指令 转化器
|
||||||
|
// Notion Agent 调用此脚本,将工单转化为铸渊可执行的下行指令
|
||||||
|
// 输入:工单 JSON 文件路径
|
||||||
|
// 输出:下行指令 JSON(写入 deploy-queue/pending/)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const DEPLOY_QUEUE = 'data/deploy-queue/pending';
|
||||||
|
const NEURAL_MAP_PATH = 'skyeye/neural-map.json';
|
||||||
|
|
||||||
|
function loadJSON(p) {
|
||||||
|
try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
|
||||||
|
catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateCommandId() {
|
||||||
|
var now = new Date();
|
||||||
|
var cst = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var date = cst.toISOString().split('T')[0].replace(/-/g, '');
|
||||||
|
var seq = crypto.randomBytes(2).toString('hex').toUpperCase();
|
||||||
|
return 'CMD-' + date + '-' + seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertWorkOrderToCommand(workOrder) {
|
||||||
|
var neuralMap = loadJSON(NEURAL_MAP_PATH);
|
||||||
|
if (!neuralMap) throw new Error('neural-map.json 不存在');
|
||||||
|
|
||||||
|
var commandId = generateCommandId();
|
||||||
|
var now = new Date().toISOString();
|
||||||
|
|
||||||
|
// 确定目标 Workflow
|
||||||
|
var targetWorkflowId = (workOrder.affected && workOrder.affected.workflows)
|
||||||
|
? workOrder.affected.workflows[0] : null;
|
||||||
|
var targetWorkflow = targetWorkflowId
|
||||||
|
? neuralMap.github_workflows[targetWorkflowId] : null;
|
||||||
|
|
||||||
|
// 确定指令类型
|
||||||
|
var instructionType = 'trigger_workflow';
|
||||||
|
var instructionParams = {};
|
||||||
|
|
||||||
|
var action = (workOrder.source && workOrder.source.rule_triggered) || '';
|
||||||
|
if (action.indexOf('cleanup') !== -1 || action.indexOf('clean') !== -1) {
|
||||||
|
instructionType = 'run_script';
|
||||||
|
instructionParams = {
|
||||||
|
script: 'scripts/neural/cleanup-old-reports.js',
|
||||||
|
args: { max_age_days: 7 }
|
||||||
|
};
|
||||||
|
} else if (action.indexOf('guard_restart') !== -1 || action.indexOf('quota') !== -1) {
|
||||||
|
instructionType = 'modify_config';
|
||||||
|
instructionParams = {
|
||||||
|
target_file: (workOrder.affected && workOrder.affected.guards && workOrder.affected.guards[0])
|
||||||
|
? 'skyeye/guards/' + workOrder.affected.guards[0] + '.json'
|
||||||
|
: null,
|
||||||
|
modifications: { status: 'active', mode: 'normal' }
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
instructionType = 'trigger_workflow';
|
||||||
|
instructionParams = {
|
||||||
|
event: 'workflow_dispatch',
|
||||||
|
inputs: {
|
||||||
|
reason: '工单 ' + workOrder.work_order_id + ' 自动触发',
|
||||||
|
source_work_order: workOrder.work_order_id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var assignedTo = (workOrder.assignment && workOrder.assignment.assigned_to) || 'AG-TY-01';
|
||||||
|
var assignedToName = (workOrder.assignment && workOrder.assignment.assigned_to_name) || '天眼 Notion 大脑';
|
||||||
|
|
||||||
|
var command = {
|
||||||
|
_protocol: 'neural-bridge-v3.0',
|
||||||
|
_type: 'downstream_command',
|
||||||
|
command_id: commandId,
|
||||||
|
parent_work_order: workOrder.work_order_id,
|
||||||
|
source: {
|
||||||
|
agent_id: assignedTo,
|
||||||
|
agent_name: assignedToName,
|
||||||
|
issued_at: now,
|
||||||
|
issued_reason: workOrder.title
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
workflow_id: targetWorkflowId || 'unknown',
|
||||||
|
workflow_file: targetWorkflow ? targetWorkflow.file : 'unknown',
|
||||||
|
brain: targetWorkflow ? targetWorkflow.brain : assignedTo
|
||||||
|
},
|
||||||
|
instruction: {
|
||||||
|
type: instructionType,
|
||||||
|
params: instructionParams
|
||||||
|
},
|
||||||
|
constraints: {
|
||||||
|
priority: workOrder.severity,
|
||||||
|
timeout_hours: (workOrder.constraints && workOrder.constraints.timeout_hours) || 24,
|
||||||
|
max_retries: (workOrder.constraints && workOrder.constraints.max_retries) || 2,
|
||||||
|
requires_human_approval: workOrder.severity === 'P0',
|
||||||
|
execution_window: {
|
||||||
|
start: '06:00 CST',
|
||||||
|
end: '23:00 CST'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expected_outcome: {
|
||||||
|
description: '解决工单 ' + workOrder.work_order_id + ': ' + workOrder.title,
|
||||||
|
verification: {
|
||||||
|
type: 'check_workflow_status',
|
||||||
|
workflow: targetWorkflowId,
|
||||||
|
expected_conclusion: 'success'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
security: {
|
||||||
|
sfp: '⌜SFP::' + assignedTo + '::NeuralBridge::' + commandId + '::' + now + '⌝',
|
||||||
|
signature_chain: [assignedTo, '铸渊桥接层']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 写入 deploy-queue
|
||||||
|
fs.mkdirSync(DEPLOY_QUEUE, { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(DEPLOY_QUEUE, commandId + '.json'),
|
||||||
|
JSON.stringify(command, null, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('✅ 工单 ' + workOrder.work_order_id + ' → 指令 ' + commandId);
|
||||||
|
console.log(' 类型: ' + instructionType);
|
||||||
|
console.log(' 目标: ' + (targetWorkflowId || '(待确定)'));
|
||||||
|
console.log(' 优先级: ' + workOrder.severity);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLI 入口
|
||||||
|
if (require.main === module) {
|
||||||
|
var woPath = process.argv[2];
|
||||||
|
if (!woPath) {
|
||||||
|
console.error('用法: node convert-workorder-to-command.js <work-order.json>');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
var wo = loadJSON(woPath);
|
||||||
|
if (!wo) {
|
||||||
|
console.error('❌ 无法读取工单文件: ' + woPath);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
convertWorkOrderToCommand(wo);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { convertWorkOrderToCommand };
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
// scripts/neural/generate-daily-digest.js
|
||||||
|
// 🧬 双端神经系统 · 每日汇总引擎
|
||||||
|
// 收集全仓库当日所有数据 → 生成标准化日报 JSON
|
||||||
|
// 这个日报是 Notion 天眼大脑的「眼睛」
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const DIGEST_DIR = '/tmp/neural-digest';
|
||||||
|
const CRITICAL_FAILURE_RATE_THRESHOLD = 20; // percentage - matches neural-analysis-rules.json P0 threshold
|
||||||
|
|
||||||
|
function loadJSON(filePath) {
|
||||||
|
try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateDigest() {
|
||||||
|
const now = new Date();
|
||||||
|
const cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
const workflowSummary = loadJSON(path.join(DIGEST_DIR, 'workflow-summary.json'));
|
||||||
|
const workflowReports = loadJSON(path.join(DIGEST_DIR, 'workflow-reports.json'));
|
||||||
|
const skyeyeLatest = loadJSON(path.join(DIGEST_DIR, 'skyeye-latest.json'));
|
||||||
|
const guardStatus = loadJSON(path.join(DIGEST_DIR, 'guard-status.json'));
|
||||||
|
const quotaStatus = loadJSON(path.join(DIGEST_DIR, 'quota-status.json'));
|
||||||
|
const neuralMap = loadJSON('skyeye/neural-map.json');
|
||||||
|
|
||||||
|
// ━━━ 按上级大脑分组统计 ━━━
|
||||||
|
const brainSummary = {};
|
||||||
|
if (neuralMap && neuralMap.github_workflows) {
|
||||||
|
for (const [wfId, wf] of Object.entries(neuralMap.github_workflows)) {
|
||||||
|
const brain = wf.brain;
|
||||||
|
if (!brainSummary[brain]) {
|
||||||
|
brainSummary[brain] = {
|
||||||
|
name: (neuralMap.notion_brains[brain] || {}).name || brain,
|
||||||
|
total_workflows: 0, healthy: 0, failed: 0, no_data: 0, workflows: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
brainSummary[brain].total_workflows++;
|
||||||
|
const wfRun = workflowSummary && workflowSummary.by_workflow ? workflowSummary.by_workflow[wf.name] : null;
|
||||||
|
const status = wfRun ? (wfRun.failure > 0 ? '❌' : '✅') : '⚠️';
|
||||||
|
if (status === '✅') brainSummary[brain].healthy++;
|
||||||
|
else if (status === '❌') brainSummary[brain].failed++;
|
||||||
|
else brainSummary[brain].no_data++;
|
||||||
|
brainSummary[brain].workflows.push({
|
||||||
|
id: wfId, name: wf.name, status,
|
||||||
|
runs: wfRun ? wfRun.runs : 0,
|
||||||
|
successes: wfRun ? wfRun.success : 0,
|
||||||
|
failures: wfRun ? wfRun.failure : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 整体健康度 ━━━
|
||||||
|
const totalWorkflows = workflowSummary ? (workflowSummary.total || 0) : 0;
|
||||||
|
const totalFailures = workflowSummary ? (workflowSummary.failure || 0) : 0;
|
||||||
|
const failureRate = totalWorkflows > 0 ? (totalFailures / totalWorkflows * 100).toFixed(1) : 0;
|
||||||
|
let overallHealth = '🟢';
|
||||||
|
if (totalFailures > 0) overallHealth = '🟡';
|
||||||
|
if (parseFloat(failureRate) > CRITICAL_FAILURE_RATE_THRESHOLD) overallHealth = '🔴';
|
||||||
|
|
||||||
|
// ━━━ Guard 汇总 ━━━
|
||||||
|
let guardsActive = 0, guardsSuspended = 0, guardsTotal = 0;
|
||||||
|
if (guardStatus) {
|
||||||
|
for (const g of Object.values(guardStatus)) {
|
||||||
|
guardsTotal++;
|
||||||
|
if (g.status === 'active') guardsActive++;
|
||||||
|
if (g.status === 'suspended' || g.mode === 'suspended') guardsSuspended++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 组装日报 ━━━
|
||||||
|
const digest = {
|
||||||
|
digest_id: 'NEURAL-DIGEST-' + cstTime.toISOString().split('T')[0],
|
||||||
|
timestamp: now.toISOString(),
|
||||||
|
timestamp_cst: cstTime.toISOString().replace('Z', '+08:00'),
|
||||||
|
version: '3.0.0',
|
||||||
|
instruction_ref: 'ZY-NEURAL-UPGRADE-2026-0325-R2-002',
|
||||||
|
overall_health: overallHealth,
|
||||||
|
failure_rate_percent: parseFloat(failureRate),
|
||||||
|
workflow_summary: {
|
||||||
|
total_runs_24h: totalWorkflows,
|
||||||
|
success: workflowSummary ? (workflowSummary.success || 0) : 0,
|
||||||
|
failure: totalFailures,
|
||||||
|
cancelled: workflowSummary ? (workflowSummary.cancelled || 0) : 0,
|
||||||
|
in_progress: workflowSummary ? (workflowSummary.in_progress || 0) : 0
|
||||||
|
},
|
||||||
|
brain_summary: brainSummary,
|
||||||
|
skyeye_status: skyeyeLatest ? {
|
||||||
|
overall_health: skyeyeLatest.overall_health,
|
||||||
|
last_scan: skyeyeLatest.timestamp,
|
||||||
|
total_issues: (skyeyeLatest.diagnosis || {}).total_issues || 0
|
||||||
|
} : { error: 'no_skyeye_report' },
|
||||||
|
guard_status: { total: guardsTotal, active: guardsActive, suspended: guardsSuspended },
|
||||||
|
quota_status: quotaStatus ? (quotaStatus.health_summary || { note: 'no health_summary field' }) : { error: 'no_quota_data' },
|
||||||
|
issues_detected: [],
|
||||||
|
recommendations: [],
|
||||||
|
neural_map_version: neuralMap ? (neuralMap.version || 'unknown') : 'missing',
|
||||||
|
unmapped_workflows: neuralMap ? (neuralMap.unmapped_workflows || []) : []
|
||||||
|
};
|
||||||
|
|
||||||
|
// ━━━ 自动检测问题 ━━━
|
||||||
|
if (overallHealth === '🔴') {
|
||||||
|
digest.issues_detected.push({
|
||||||
|
severity: 'P0',
|
||||||
|
description: 'Workflow 失败率 ' + failureRate + '% 超过 20% 阈值',
|
||||||
|
recommendation: '立即排查失败的 Workflow'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (guardsSuspended > 0) {
|
||||||
|
digest.issues_detected.push({
|
||||||
|
severity: 'P1',
|
||||||
|
description: guardsSuspended + ' 个 Guard 被暂停',
|
||||||
|
recommendation: '检查被暂停的 Guard'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (digest.unmapped_workflows.length > 0) {
|
||||||
|
digest.issues_detected.push({
|
||||||
|
severity: 'P1',
|
||||||
|
description: '发现 ' + digest.unmapped_workflows.length + ' 个孤儿 Workflow',
|
||||||
|
recommendation: '在 neural-map.json 中分配上级大脑'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(DIGEST_DIR, { recursive: true });
|
||||||
|
fs.writeFileSync(path.join(DIGEST_DIR, 'daily-digest.json'), JSON.stringify(digest, null, 2));
|
||||||
|
|
||||||
|
console.log('\n━━━ 🧬 双端神经系统·日报摘要 ━━━');
|
||||||
|
console.log('整体健康:' + overallHealth);
|
||||||
|
console.log('24h运行:' + digest.workflow_summary.total_runs_24h + ' 次');
|
||||||
|
console.log('Guard:' + guardsActive + '/' + guardsTotal + ' 活跃');
|
||||||
|
console.log('问题:' + digest.issues_detected.length + ' 个');
|
||||||
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
generateDigest();
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// scripts/neural/sync-digest-to-notion.js
|
||||||
|
// 🧬 将仓库日报推送到 Notion 天眼大脑
|
||||||
|
// 推送方式(按优先级):
|
||||||
|
// 1. Notion API 直写(如有写权限)
|
||||||
|
// 2. 写入 .github/notion-cache/neural-digest/(兜底)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const NOTION_TOKEN = process.env.NOTION_TOKEN;
|
||||||
|
const DIGEST_PATH = '/tmp/neural-digest/daily-digest.json';
|
||||||
|
const CACHE_DIR = '.github/notion-cache/neural-digest';
|
||||||
|
|
||||||
|
async function syncToNotion() {
|
||||||
|
const digest = JSON.parse(fs.readFileSync(DIGEST_PATH, 'utf8'));
|
||||||
|
console.log('📡 推送日报 ' + digest.digest_id + ' 到 Notion...');
|
||||||
|
|
||||||
|
var notionSuccess = false;
|
||||||
|
|
||||||
|
if (NOTION_TOKEN) {
|
||||||
|
try {
|
||||||
|
// 铸渊根据实际 Notion 结构选择最优推送方式
|
||||||
|
// 方式1:更新天眼页面的指定 block
|
||||||
|
// 方式2:创建日报数据库条目
|
||||||
|
console.log('⚠️ Notion API 推送逻辑待实现,使用缓存兜底');
|
||||||
|
} catch (e) {
|
||||||
|
console.log('❌ Notion API 推送失败: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兜底:写入缓存
|
||||||
|
if (!notionSuccess) {
|
||||||
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
||||||
|
var date = digest.digest_id.replace('NEURAL-DIGEST-', '');
|
||||||
|
fs.writeFileSync(CACHE_DIR + '/digest-' + date + '.json', JSON.stringify(digest, null, 2));
|
||||||
|
console.log('💾 日报已缓存到 ' + CACHE_DIR + '/digest-' + date + '.json');
|
||||||
|
console.log('📌 霜砚下次醒来会读取此缓存');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 memory.json
|
||||||
|
var memoryPath = '.github/persona-brain/memory.json';
|
||||||
|
if (fs.existsSync(memoryPath)) {
|
||||||
|
try {
|
||||||
|
var memory = JSON.parse(fs.readFileSync(memoryPath, 'utf8'));
|
||||||
|
memory.neural_digest = {
|
||||||
|
last_digest_id: digest.digest_id,
|
||||||
|
last_digest_time: digest.timestamp,
|
||||||
|
overall_health: digest.overall_health,
|
||||||
|
notion_sync: notionSuccess ? 'success' : 'cached',
|
||||||
|
issues_count: digest.issues_detected.length
|
||||||
|
};
|
||||||
|
fs.writeFileSync(memoryPath, JSON.stringify(memory, null, 2));
|
||||||
|
console.log('✅ memory.json 已更新');
|
||||||
|
} catch (e) {
|
||||||
|
console.log('⚠️ memory.json 更新失败: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncToNotion().catch(function(err) {
|
||||||
|
console.error('❌ 日报推送失败:', err);
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,224 @@
|
||||||
|
// scripts/neural/track-work-orders.js
|
||||||
|
// 🧬 工单追踪器
|
||||||
|
// 铸渊每次唤醒时运行,追踪所有活跃工单状态
|
||||||
|
// 检查超时、匹配回执、更新状态、生成追踪报告
|
||||||
|
//
|
||||||
|
// 指令回执追踪表配置(Notion 侧)
|
||||||
|
// 数据库位置:光湖语言壳 > 统一网关 > 指令回执追踪表
|
||||||
|
// 写入脚本:scripts/neural/write-receipt-to-notion.js
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
var WORK_ORDER_DIR = 'data/neural-reports/work-orders';
|
||||||
|
var COMPLETED_DIR = 'data/deploy-queue/completed';
|
||||||
|
var RECEIPT_DIR = 'data/neural-reports/receipts';
|
||||||
|
var TRACKER_DIR = 'data/neural-reports/work-orders';
|
||||||
|
var TERMINAL_STATUSES = ['CLOSED', 'ESCALATED', 'VERIFIED'];
|
||||||
|
|
||||||
|
// ━━━ 指令回执追踪配置 ━━━
|
||||||
|
var RECEIPT_TRACKER_CONFIG = {
|
||||||
|
// 指令回执追踪表 · Notion Database ID
|
||||||
|
// 位于:光湖语言壳 > 统一网关 > 指令回执追踪表
|
||||||
|
// 实际 Database ID 通过此环境变量名读取(安全考虑不硬编码)
|
||||||
|
databaseIdEnvVar: 'RECEIPT_DB_ID',
|
||||||
|
|
||||||
|
// 字段映射(与 Notion 数据库字段名一一对应)
|
||||||
|
fieldMap: {
|
||||||
|
instructionId: '指令编号', // title
|
||||||
|
summary: '指令摘要', // text
|
||||||
|
status: '执行状态', // status
|
||||||
|
receipt: '铸渊回执', // text
|
||||||
|
receiptTime: '回执时间', // date
|
||||||
|
newFiles: '新增文件数', // number
|
||||||
|
modifiedFiles: '修改文件数', // number
|
||||||
|
relatedAgent: '关联Agent', // text
|
||||||
|
timeoutStatus: '回执超时', // select
|
||||||
|
},
|
||||||
|
|
||||||
|
// 超时阈值(小时)
|
||||||
|
timeoutThresholds: {
|
||||||
|
warning: 24, // 24h → 🟡 接近超时
|
||||||
|
critical: 72, // 72h → 🔴 已超时
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadJSON(p) {
|
||||||
|
try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
|
||||||
|
catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveWorkOrders() {
|
||||||
|
if (!fs.existsSync(WORK_ORDER_DIR)) return [];
|
||||||
|
|
||||||
|
var allOrders = [];
|
||||||
|
var files = fs.readdirSync(WORK_ORDER_DIR)
|
||||||
|
.filter(function(f) { return f.startsWith('work-orders-') && f.endsWith('.json'); });
|
||||||
|
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var data = loadJSON(path.join(WORK_ORDER_DIR, files[i]));
|
||||||
|
if (data && data.work_orders) {
|
||||||
|
for (var j = 0; j < data.work_orders.length; j++) {
|
||||||
|
allOrders.push(data.work_orders[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allOrders.filter(function(wo) {
|
||||||
|
return TERMINAL_STATUSES.indexOf(wo.status) === -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompletedReceipts() {
|
||||||
|
var receipts = {};
|
||||||
|
|
||||||
|
// 从 deploy-queue/completed 收集
|
||||||
|
if (fs.existsSync(COMPLETED_DIR)) {
|
||||||
|
var files = fs.readdirSync(COMPLETED_DIR)
|
||||||
|
.filter(function(f) { return f.endsWith('.json'); });
|
||||||
|
|
||||||
|
for (var i = 0; i < files.length; i++) {
|
||||||
|
var receipt = loadJSON(path.join(COMPLETED_DIR, files[i]));
|
||||||
|
if (receipt && receipt.command_id) {
|
||||||
|
receipts[receipt.command_id] = receipt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 neural-reports/receipts 收集本地回执
|
||||||
|
if (fs.existsSync(RECEIPT_DIR)) {
|
||||||
|
var receiptFiles = fs.readdirSync(RECEIPT_DIR)
|
||||||
|
.filter(function(f) { return f.endsWith('.json'); });
|
||||||
|
|
||||||
|
for (var j = 0; j < receiptFiles.length; j++) {
|
||||||
|
var localReceipt = loadJSON(path.join(RECEIPT_DIR, receiptFiles[j]));
|
||||||
|
if (localReceipt && localReceipt.instruction_id) {
|
||||||
|
receipts[localReceipt.instruction_id] = localReceipt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return receipts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTimeout(workOrder) {
|
||||||
|
var timeout = workOrder.timeout_hours || RECEIPT_TRACKER_CONFIG.timeoutThresholds.critical;
|
||||||
|
var created = new Date(workOrder.created);
|
||||||
|
var now = new Date();
|
||||||
|
var elapsed = (now - created) / (1000 * 60 * 60);
|
||||||
|
return elapsed > timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeoutStatus(workOrder) {
|
||||||
|
var created = new Date(workOrder.created);
|
||||||
|
var now = new Date();
|
||||||
|
var elapsed = (now - created) / (1000 * 60 * 60);
|
||||||
|
|
||||||
|
if (elapsed > RECEIPT_TRACKER_CONFIG.timeoutThresholds.critical) return '🔴 已超时';
|
||||||
|
if (elapsed > RECEIPT_TRACKER_CONFIG.timeoutThresholds.warning) return '🟡 接近超时';
|
||||||
|
return '🟢 正常';
|
||||||
|
}
|
||||||
|
|
||||||
|
function trackWorkOrders() {
|
||||||
|
console.log('\n━━━ 🧬 工单追踪器启动 ━━━\n');
|
||||||
|
|
||||||
|
var activeOrders = getActiveWorkOrders();
|
||||||
|
var receipts = getCompletedReceipts();
|
||||||
|
|
||||||
|
console.log('活跃工单: ' + activeOrders.length + ' 个');
|
||||||
|
|
||||||
|
var stats = {
|
||||||
|
total_active: activeOrders.length,
|
||||||
|
by_status: {},
|
||||||
|
timed_out: 0,
|
||||||
|
matched_receipts: 0,
|
||||||
|
escalated: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < activeOrders.length; i++) {
|
||||||
|
var wo = activeOrders[i];
|
||||||
|
var status = wo.status || 'pending';
|
||||||
|
|
||||||
|
// 统计状态分布
|
||||||
|
if (!stats.by_status[status]) stats.by_status[status] = 0;
|
||||||
|
stats.by_status[status]++;
|
||||||
|
|
||||||
|
// 检查超时
|
||||||
|
if (checkTimeout(wo)) {
|
||||||
|
stats.timed_out++;
|
||||||
|
console.log(' ⏰ 超时: ' + wo.id + ' (' + wo.title + ')');
|
||||||
|
|
||||||
|
// 检查是否需要升级
|
||||||
|
var maxRetries = (wo.constraints && wo.constraints.max_retries) || 2;
|
||||||
|
if (wo.retry_count >= maxRetries) {
|
||||||
|
wo.status = 'ESCALATED';
|
||||||
|
stats.escalated++;
|
||||||
|
console.log(' 🔺 升级到人类: ' + wo.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查回执匹配
|
||||||
|
if (wo.command_id && receipts[wo.command_id]) {
|
||||||
|
var receipt = receipts[wo.command_id];
|
||||||
|
stats.matched_receipts++;
|
||||||
|
|
||||||
|
if (receipt.result && receipt.result.status === 'success') {
|
||||||
|
wo.status = 'VERIFIED';
|
||||||
|
console.log(' ✅ 已验证: ' + wo.id + ' (回执成功)');
|
||||||
|
} else if (receipt.result && receipt.result.status === 'failure') {
|
||||||
|
wo.status = 'pending';
|
||||||
|
wo.retry_count = (wo.retry_count || 0) + 1;
|
||||||
|
console.log(' ❌ 失败: ' + wo.id + ' (重试 ' + wo.retry_count + ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成追踪报告
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var dateStr = cstTime.toISOString().split('T')[0];
|
||||||
|
|
||||||
|
var trackerReport = {
|
||||||
|
tracker_id: 'TRACKER-' + dateStr,
|
||||||
|
timestamp: now.toISOString(),
|
||||||
|
receipt_config: {
|
||||||
|
database_env_var: RECEIPT_TRACKER_CONFIG.databaseIdEnvVar,
|
||||||
|
timeout_warning_hours: RECEIPT_TRACKER_CONFIG.timeoutThresholds.warning,
|
||||||
|
timeout_critical_hours: RECEIPT_TRACKER_CONFIG.timeoutThresholds.critical
|
||||||
|
},
|
||||||
|
stats: stats,
|
||||||
|
active_orders: activeOrders.map(function(wo) {
|
||||||
|
return {
|
||||||
|
id: wo.id,
|
||||||
|
severity: wo.severity,
|
||||||
|
title: wo.title,
|
||||||
|
status: wo.status,
|
||||||
|
created: wo.created,
|
||||||
|
timed_out: checkTimeout(wo),
|
||||||
|
timeout_status: getTimeoutStatus(wo)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.mkdirSync(TRACKER_DIR, { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(TRACKER_DIR, 'tracker-' + dateStr + '.json'),
|
||||||
|
JSON.stringify(trackerReport, null, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('\n📊 追踪报告:');
|
||||||
|
console.log(' 活跃: ' + stats.total_active);
|
||||||
|
console.log(' 超时: ' + stats.timed_out);
|
||||||
|
console.log(' 回执匹配: ' + stats.matched_receipts);
|
||||||
|
console.log(' 升级: ' + stats.escalated);
|
||||||
|
console.log(' 状态分布: ' + JSON.stringify(stats.by_status));
|
||||||
|
console.log('\n━━━ 追踪完成 ━━━\n');
|
||||||
|
|
||||||
|
return trackerReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
trackWorkOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { trackWorkOrders, RECEIPT_TRACKER_CONFIG };
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
// scripts/neural/write-receipt-to-notion.js
|
||||||
|
// 📡 指令回执自动写入 Notion
|
||||||
|
// 铸渊每次执行完指令后,自动将回执写入 Notion「指令回执追踪表」
|
||||||
|
// 实现 指令→执行→回执 全链路自动闭环
|
||||||
|
//
|
||||||
|
// 用法:
|
||||||
|
// node scripts/neural/write-receipt-to-notion.js \
|
||||||
|
// --instruction-id "ZY-XXX" \
|
||||||
|
// --status "success" \
|
||||||
|
// --workflow "workflow-name" \
|
||||||
|
// [--summary "执行摘要"] \
|
||||||
|
// [--receipt "回执详情"] \
|
||||||
|
// [--new-files 0] \
|
||||||
|
// [--modified-files 0] \
|
||||||
|
// [--related-agent "AG-TY-01"]
|
||||||
|
//
|
||||||
|
// 环境变量:
|
||||||
|
// NOTION_API_KEY — Notion API 密钥(必须)
|
||||||
|
// RECEIPT_DB_ID — 指令回执追踪表的 Notion Database ID(必须)
|
||||||
|
//
|
||||||
|
// 铁律:
|
||||||
|
// 1. 写入失败不阻塞主流程
|
||||||
|
// 2. 同一指令编号幂等(重复写入 = 更新)
|
||||||
|
// 3. 失败时写入本地 SYSLOG 报错
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var https = require('https');
|
||||||
|
|
||||||
|
// ━━━ 配置 ━━━
|
||||||
|
|
||||||
|
var RECEIPT_TRACKER_CONFIG = {
|
||||||
|
// 字段映射 — Notion 数据库字段名
|
||||||
|
fieldMap: {
|
||||||
|
instructionId: '指令编号',
|
||||||
|
summary: '指令摘要',
|
||||||
|
status: '执行状态',
|
||||||
|
receipt: '铸渊回执',
|
||||||
|
receiptTime: '回执时间',
|
||||||
|
newFiles: '新增文件数',
|
||||||
|
modifiedFiles: '修改文件数',
|
||||||
|
relatedAgent: '关联Agent',
|
||||||
|
timeoutStatus: '回执超时'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 超时阈值(小时)
|
||||||
|
timeoutThresholds: {
|
||||||
|
warning: 24,
|
||||||
|
critical: 72
|
||||||
|
},
|
||||||
|
|
||||||
|
// 状态映射
|
||||||
|
statusMap: {
|
||||||
|
'success': '✅ 已完成',
|
||||||
|
'failure': '❌ 执行失败',
|
||||||
|
'cancelled': '⏸️ 已挂起',
|
||||||
|
'skipped': '⏸️ 已挂起'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var LOCAL_RECEIPT_DIR = 'data/neural-reports/receipts';
|
||||||
|
var SYSLOG_DIR = 'data/neural-reports/syslog';
|
||||||
|
|
||||||
|
// ━━━ 参数解析 ━━━
|
||||||
|
|
||||||
|
function parseArgs() {
|
||||||
|
var args = process.argv.slice(2);
|
||||||
|
var parsed = {};
|
||||||
|
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--instruction-id' && args[i + 1]) {
|
||||||
|
parsed.instructionId = args[++i];
|
||||||
|
} else if (args[i] === '--status' && args[i + 1]) {
|
||||||
|
parsed.status = args[++i];
|
||||||
|
} else if (args[i] === '--workflow' && args[i + 1]) {
|
||||||
|
parsed.workflow = args[++i];
|
||||||
|
} else if (args[i] === '--summary' && args[i + 1]) {
|
||||||
|
parsed.summary = args[++i];
|
||||||
|
} else if (args[i] === '--receipt' && args[i + 1]) {
|
||||||
|
parsed.receipt = args[++i];
|
||||||
|
} else if (args[i] === '--new-files' && args[i + 1]) {
|
||||||
|
parsed.newFiles = parseInt(args[++i], 10) || 0;
|
||||||
|
} else if (args[i] === '--modified-files' && args[i + 1]) {
|
||||||
|
parsed.modifiedFiles = parseInt(args[++i], 10) || 0;
|
||||||
|
} else if (args[i] === '--related-agent' && args[i + 1]) {
|
||||||
|
parsed.relatedAgent = args[++i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ Notion API 封装(纯 https,无外部依赖)━━━
|
||||||
|
|
||||||
|
function notionRequest(method, endpoint, body, token) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
var bodyStr = body ? JSON.stringify(body) : '';
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
hostname: 'api.notion.com',
|
||||||
|
port: 443,
|
||||||
|
path: '/v1' + endpoint,
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer ' + token,
|
||||||
|
'Notion-Version': '2022-06-28',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(bodyStr)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var req = https.request(options, 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 response parse error: ' + data.substring(0, 200)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', function(e) {
|
||||||
|
reject(new Error('Notion API request error: ' + e.message));
|
||||||
|
});
|
||||||
|
|
||||||
|
req.setTimeout(30000, function() {
|
||||||
|
req.destroy();
|
||||||
|
reject(new Error('Notion API request timeout (30s)'));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bodyStr) req.write(bodyStr);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ Notion 属性构建 ━━━
|
||||||
|
|
||||||
|
function buildNotionProperties(receipt) {
|
||||||
|
var fm = RECEIPT_TRACKER_CONFIG.fieldMap;
|
||||||
|
var statusText = RECEIPT_TRACKER_CONFIG.statusMap[receipt.status] || '⏸️ 已挂起';
|
||||||
|
|
||||||
|
var properties = {};
|
||||||
|
|
||||||
|
// 指令编号 (title)
|
||||||
|
properties[fm.instructionId] = {
|
||||||
|
title: [{ text: { content: receipt.instructionId || 'AUTO' } }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 指令摘要 (rich_text)
|
||||||
|
properties[fm.summary] = {
|
||||||
|
rich_text: [{ text: { content: receipt.summary || receipt.workflow || '' } }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 执行状态 (status)
|
||||||
|
properties[fm.status] = {
|
||||||
|
status: { name: statusText }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 铸渊回执 (rich_text)
|
||||||
|
var receiptText = receipt.receipt || (statusText + ' · ' + (receipt.workflow || ''));
|
||||||
|
properties[fm.receipt] = {
|
||||||
|
rich_text: [{ text: { content: receiptText.substring(0, 2000) } }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 回执时间 (date)
|
||||||
|
properties[fm.receiptTime] = {
|
||||||
|
date: { start: new Date().toISOString().split('T')[0] }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增文件数 (number)
|
||||||
|
if (typeof receipt.newFiles === 'number') {
|
||||||
|
properties[fm.newFiles] = { number: receipt.newFiles };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改文件数 (number)
|
||||||
|
if (typeof receipt.modifiedFiles === 'number') {
|
||||||
|
properties[fm.modifiedFiles] = { number: receipt.modifiedFiles };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关联Agent (rich_text)
|
||||||
|
if (receipt.relatedAgent) {
|
||||||
|
properties[fm.relatedAgent] = {
|
||||||
|
rich_text: [{ text: { content: receipt.relatedAgent } }]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回执超时 (select)
|
||||||
|
properties[fm.timeoutStatus] = {
|
||||||
|
select: { name: '🟢 正常' }
|
||||||
|
};
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 写入 Notion ━━━
|
||||||
|
|
||||||
|
async function writeReceiptToNotion(receipt, token, databaseId) {
|
||||||
|
console.log('📡 写入回执到 Notion · 指令: ' + receipt.instructionId);
|
||||||
|
|
||||||
|
// 先查询是否已有该指令编号的记录(幂等)
|
||||||
|
var queryBody = {
|
||||||
|
database_id: databaseId,
|
||||||
|
filter: {
|
||||||
|
property: RECEIPT_TRACKER_CONFIG.fieldMap.instructionId,
|
||||||
|
title: { equals: receipt.instructionId }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var existing = await notionRequest('POST', '/databases/' + databaseId + '/query', queryBody, token);
|
||||||
|
|
||||||
|
var properties = buildNotionProperties(receipt);
|
||||||
|
|
||||||
|
if (existing.results && existing.results.length > 0) {
|
||||||
|
// 更新已有记录
|
||||||
|
var pageId = existing.results[0].id;
|
||||||
|
await notionRequest('PATCH', '/pages/' + pageId, { properties: properties }, token);
|
||||||
|
console.log('✅ 已更新现有记录: ' + pageId);
|
||||||
|
} else {
|
||||||
|
// 创建新记录
|
||||||
|
await notionRequest('POST', '/pages', {
|
||||||
|
parent: { database_id: databaseId },
|
||||||
|
properties: properties
|
||||||
|
}, token);
|
||||||
|
console.log('✅ 已创建新记录');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 本地兜底写入 ━━━
|
||||||
|
|
||||||
|
function writeLocalReceipt(receipt) {
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(LOCAL_RECEIPT_DIR, { recursive: true });
|
||||||
|
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var dateStr = cstTime.toISOString().split('T')[0];
|
||||||
|
var timeStr = cstTime.toISOString().replace(/[-:]/g, '').split('.')[0];
|
||||||
|
|
||||||
|
var filename = 'receipt-' + timeStr + '.json';
|
||||||
|
var fullPath = path.join(LOCAL_RECEIPT_DIR, filename);
|
||||||
|
|
||||||
|
var localReceipt = {
|
||||||
|
instruction_id: receipt.instructionId,
|
||||||
|
workflow: receipt.workflow,
|
||||||
|
status: receipt.status,
|
||||||
|
summary: receipt.summary || '',
|
||||||
|
receipt_text: receipt.receipt || '',
|
||||||
|
new_files: receipt.newFiles || 0,
|
||||||
|
modified_files: receipt.modifiedFiles || 0,
|
||||||
|
related_agent: receipt.relatedAgent || '',
|
||||||
|
timestamp: now.toISOString(),
|
||||||
|
notion_synced: false
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFileSync(fullPath, JSON.stringify(localReceipt, null, 2));
|
||||||
|
console.log('💾 本地回执已保存: ' + fullPath);
|
||||||
|
return fullPath;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ 本地回执保存失败: ' + e.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ SYSLOG 报错 ━━━
|
||||||
|
|
||||||
|
function writeSyslogError(message, receipt) {
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(SYSLOG_DIR, { recursive: true });
|
||||||
|
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var timeStr = cstTime.toISOString().replace(/[-:]/g, '').split('.')[0];
|
||||||
|
|
||||||
|
var logEntry = {
|
||||||
|
level: 'ERROR',
|
||||||
|
source: 'write-receipt-to-notion',
|
||||||
|
message: message,
|
||||||
|
instruction_id: receipt ? receipt.instructionId : 'unknown',
|
||||||
|
timestamp: now.toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
var filename = 'receipt-error-' + timeStr + '.json';
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(SYSLOG_DIR, filename),
|
||||||
|
JSON.stringify(logEntry, null, 2)
|
||||||
|
);
|
||||||
|
console.error('📝 错误已记录到 SYSLOG: ' + filename);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('⚠️ SYSLOG 写入也失败: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ━━━ 主函数 ━━━
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('\n━━━ 📡 指令回执写入 ━━━\n');
|
||||||
|
|
||||||
|
var receipt = parseArgs();
|
||||||
|
|
||||||
|
if (!receipt.instructionId && !receipt.workflow) {
|
||||||
|
console.log('⚠️ 未提供 instruction-id 或 workflow,跳过回执写入');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有指令ID,用 workflow + 日期 自动生成
|
||||||
|
if (!receipt.instructionId || receipt.instructionId === 'AUTO') {
|
||||||
|
var now = new Date();
|
||||||
|
var cstTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
||||||
|
var dateStr = cstTime.toISOString().split('T')[0].replace(/-/g, '');
|
||||||
|
receipt.instructionId = 'AUTO-' + (receipt.workflow || 'unknown') + '-' + dateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 始终写入本地兜底
|
||||||
|
writeLocalReceipt(receipt);
|
||||||
|
|
||||||
|
// 尝试写入 Notion
|
||||||
|
var token = process.env.NOTION_API_KEY;
|
||||||
|
var databaseId = process.env.RECEIPT_DB_ID;
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
var msg = '⚠️ NOTION_API_KEY 未设置,仅保存本地回执';
|
||||||
|
console.log(msg);
|
||||||
|
writeSyslogError(msg, receipt);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!databaseId) {
|
||||||
|
var msg = '⚠️ RECEIPT_DB_ID 未设置,仅保存本地回执';
|
||||||
|
console.log(msg);
|
||||||
|
writeSyslogError(msg, receipt);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await writeReceiptToNotion(receipt, token, databaseId);
|
||||||
|
console.log('\n✅ 回执写入完成\n');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Notion 写入失败: ' + e.message);
|
||||||
|
writeSyslogError('Notion 写入失败: ' + e.message, receipt);
|
||||||
|
// 不阻塞主流程,退出码 0
|
||||||
|
console.log('💾 已有本地兜底,不影响主流程');
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(function(err) {
|
||||||
|
console.error('❌ 回执脚本异常: ' + err.message);
|
||||||
|
process.exit(0); // 不阻塞
|
||||||
|
});
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"last_scan": "2026-03-24T04:24:59.723Z",
|
"last_scan": "2026-03-25T06:22:39.127Z",
|
||||||
"last_scan_by": "skyeye-scan-engine",
|
"last_scan_by": "skyeye-scan-engine",
|
||||||
"infrastructure": {
|
"infrastructure": {
|
||||||
"github": {
|
"github": {
|
||||||
|
|
@ -114,7 +114,10 @@
|
||||||
"hibernate_exempt": true,
|
"hibernate_exempt": true,
|
||||||
"priority": "P0",
|
"priority": "P0",
|
||||||
"alert_on_failure": true,
|
"alert_on_failure": true,
|
||||||
"alert_channels": ["notion-dashboard", "agent-bulletin"]
|
"alert_channels": [
|
||||||
|
"notion-dashboard",
|
||||||
|
"agent-bulletin"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "TOKEN-HEALTH",
|
"id": "TOKEN-HEALTH",
|
||||||
|
|
@ -123,7 +126,10 @@
|
||||||
"hibernate_exempt": true,
|
"hibernate_exempt": true,
|
||||||
"priority": "P0",
|
"priority": "P0",
|
||||||
"alert_on_failure": true,
|
"alert_on_failure": true,
|
||||||
"alert_channels": ["notion-dashboard", "agent-bulletin"]
|
"alert_channels": [
|
||||||
|
"notion-dashboard",
|
||||||
|
"agent-bulletin"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "NIGHTLY-REPAIR",
|
"id": "NIGHTLY-REPAIR",
|
||||||
|
|
@ -132,7 +138,10 @@
|
||||||
"hibernate_exempt": true,
|
"hibernate_exempt": true,
|
||||||
"priority": "P0",
|
"priority": "P0",
|
||||||
"alert_on_failure": true,
|
"alert_on_failure": true,
|
||||||
"alert_channels": ["dashboard", "agent-bulletin"],
|
"alert_channels": [
|
||||||
|
"dashboard",
|
||||||
|
"agent-bulletin"
|
||||||
|
],
|
||||||
"note": "周六休眠期内仅执行扫描+仪表盘更新,跳过修复/PR"
|
"note": "周六休眠期内仅执行扫描+仪表盘更新,跳过修复/PR"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -213,7 +222,10 @@
|
||||||
"nightly_scan": "每天 23:00 CST (15:00 UTC)",
|
"nightly_scan": "每天 23:00 CST (15:00 UTC)",
|
||||||
"merge_watchdog": "事件驱动(PR合并时触发)"
|
"merge_watchdog": "事件驱动(PR合并时触发)"
|
||||||
},
|
},
|
||||||
"agents": ["AG-ZY-087", "AG-ZY-088"]
|
"agents": [
|
||||||
|
"AG-ZY-087",
|
||||||
|
"AG-ZY-088"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sync_dev_status": {
|
"sync_dev_status": {
|
||||||
"node_id": "SYNC-DEV-STATUS-V1",
|
"node_id": "SYNC-DEV-STATUS-V1",
|
||||||
|
|
@ -227,7 +239,10 @@
|
||||||
"data_file": ".github/persona-brain/dev-status.json",
|
"data_file": ".github/persona-brain/dev-status.json",
|
||||||
"sync_log": ".github/persona-brain/dev-status-sync-log.json",
|
"sync_log": ".github/persona-brain/dev-status-sync-log.json",
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"sync": ["09:00 CST (01:00 UTC)", "22:00 CST (14:00 UTC)"],
|
"sync": [
|
||||||
|
"09:00 CST (01:00 UTC)",
|
||||||
|
"22:00 CST (14:00 UTC)"
|
||||||
|
],
|
||||||
"monitor": "08:30 CST (00:30 UTC)"
|
"monitor": "08:30 CST (00:30 UTC)"
|
||||||
},
|
},
|
||||||
"thresholds": {
|
"thresholds": {
|
||||||
|
|
@ -254,11 +269,31 @@
|
||||||
"ssl": "Let's Encrypt (pending)"
|
"ssl": "Let's Encrypt (pending)"
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"api_proxy": { "port": 3721, "name": "guanghulab-proxy", "desc": "AI 聊天代理 SSE" },
|
"api_proxy": {
|
||||||
"backend": { "port": 3000, "name": "guanghulab-backend", "desc": "Express 主后端" },
|
"port": 3721,
|
||||||
"hli": { "port": 3001, "name": "guanghulab", "desc": "HLI 中间层" },
|
"name": "guanghulab-proxy",
|
||||||
"persona_studio": { "port": 3002, "name": "persona-studio", "desc": "Persona Studio 后端" },
|
"desc": "AI 聊天代理 SSE"
|
||||||
"websocket": { "port": 8080, "name": "guanghulab-ws", "desc": "看板 WebSocket" }
|
},
|
||||||
|
"backend": {
|
||||||
|
"port": 3000,
|
||||||
|
"name": "guanghulab-backend",
|
||||||
|
"desc": "Express 主后端"
|
||||||
|
},
|
||||||
|
"hli": {
|
||||||
|
"port": 3001,
|
||||||
|
"name": "guanghulab",
|
||||||
|
"desc": "HLI 中间层"
|
||||||
|
},
|
||||||
|
"persona_studio": {
|
||||||
|
"port": 3002,
|
||||||
|
"name": "persona-studio",
|
||||||
|
"desc": "Persona Studio 后端"
|
||||||
|
},
|
||||||
|
"websocket": {
|
||||||
|
"port": 8080,
|
||||||
|
"name": "guanghulab-ws",
|
||||||
|
"desc": "看板 WebSocket"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cd_workflow": "deploy-to-server.yml",
|
"cd_workflow": "deploy-to-server.yml",
|
||||||
"guard": "skyeye/guards/web-deploy-guard.json",
|
"guard": "skyeye/guards/web-deploy-guard.json",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,305 @@
|
||||||
|
{
|
||||||
|
"scan_id": "SCAN-20260325",
|
||||||
|
"mode": "full",
|
||||||
|
"timestamp": "2026-03-25T06:22:39.125Z",
|
||||||
|
"guard_scan": {
|
||||||
|
"total": 6,
|
||||||
|
"valid": 5,
|
||||||
|
"invalid": [],
|
||||||
|
"missing_fields": [
|
||||||
|
{
|
||||||
|
"file": "web-deploy-guard.json",
|
||||||
|
"missing": [
|
||||||
|
"quota_policy"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"workflow_scan": {
|
||||||
|
"total": 96,
|
||||||
|
"files": [
|
||||||
|
"agent-checkin.yml",
|
||||||
|
"auto-deploy-drive-bridge.yml",
|
||||||
|
"auto-reply-discussions.yml",
|
||||||
|
"bingshuo-deploy-agent.yml",
|
||||||
|
"bingshuo-neural-system.yml",
|
||||||
|
"brain-sync.yml",
|
||||||
|
"bridge-broadcast-pdf.yml",
|
||||||
|
"bridge-changes-to-notion.yml",
|
||||||
|
"bridge-heartbeat.yml",
|
||||||
|
"bridge-session-summary.yml",
|
||||||
|
"bridge-syslog-intake.yml",
|
||||||
|
"bridge-syslog-to-notion.yml",
|
||||||
|
"buffer-collect.yml",
|
||||||
|
"buffer-flush.yml",
|
||||||
|
"check-structure.yml",
|
||||||
|
"check-token-health.yml",
|
||||||
|
"daily-maintenance.yml",
|
||||||
|
"daily-report.yml",
|
||||||
|
"deploy-pages.yml",
|
||||||
|
"deploy-to-server.yml",
|
||||||
|
"distribute-broadcasts.yml",
|
||||||
|
"esp-signal-processor.yml",
|
||||||
|
"execution-sync.yml",
|
||||||
|
"federation-bridge.yml",
|
||||||
|
"feishu-syslog-bridge.yml",
|
||||||
|
"generate-module-doc.yml",
|
||||||
|
"grid-db-archive.yml",
|
||||||
|
"grid-db-processor.yml",
|
||||||
|
"grid-db-training-extract.yml",
|
||||||
|
"hli-contract-check.yml",
|
||||||
|
"merge-watchdog.yml",
|
||||||
|
"meta-watchdog.yml",
|
||||||
|
"multi-persona-awakening.yml",
|
||||||
|
"neural-daily-digest.yml",
|
||||||
|
"notion-callback-pipeline.yml",
|
||||||
|
"notion-connectivity-test.yml",
|
||||||
|
"notion-heartbeat.yml",
|
||||||
|
"notion-page-reader.yml",
|
||||||
|
"notion-poll.yml",
|
||||||
|
"notion-wake-listener.yml",
|
||||||
|
"openclaw-wake-loop.yml",
|
||||||
|
"persona-invoke.yml",
|
||||||
|
"persona-thinking-window.yml",
|
||||||
|
"pm2-server-diagnose.yml",
|
||||||
|
"process-notion-orders.yml",
|
||||||
|
"ps-on-build.yml",
|
||||||
|
"ps-on-chat.yml",
|
||||||
|
"ps-on-complete.yml",
|
||||||
|
"ps-on-login.yml",
|
||||||
|
"psp-daily-inspection.yml",
|
||||||
|
"pull-sync-awen.yml",
|
||||||
|
"push-broadcast-feishu.yml",
|
||||||
|
"push-broadcast.yml",
|
||||||
|
"readme-ui-refresh.yml",
|
||||||
|
"receive-spoke-checkin.yml",
|
||||||
|
"receive-syslog.yml",
|
||||||
|
"renew-gdrive-tokens.yml",
|
||||||
|
"sandbox-deploy.yml",
|
||||||
|
"server-patrol.yml",
|
||||||
|
"skyeye-checkin-audit.yml",
|
||||||
|
"skyeye-checkin-receiver.yml",
|
||||||
|
"skyeye-credential-audit.yml",
|
||||||
|
"skyeye-daily-hibernation.yml",
|
||||||
|
"skyeye-devsync-repair.yml",
|
||||||
|
"skyeye-weekly-hibernation.yml",
|
||||||
|
"skyeye-weekly-scan.yml",
|
||||||
|
"staging-preview.yml",
|
||||||
|
"sync-deploy-to-notion.yml",
|
||||||
|
"sync-dev-status.yml",
|
||||||
|
"sync-griddb-to-drive.yml",
|
||||||
|
"sync-griddb-to-notion.yml",
|
||||||
|
"sync-login-entry.yml",
|
||||||
|
"sync-notion-profiles.yml",
|
||||||
|
"sync-notion-to-griddb.yml",
|
||||||
|
"sync-persona-studio.yml",
|
||||||
|
"sync-repo-to-drive.yml",
|
||||||
|
"syslog-auto-pipeline.yml",
|
||||||
|
"syslog-issue-pipeline.yml",
|
||||||
|
"syslog-pipeline.yml",
|
||||||
|
"tcs-semantic-landing.yml",
|
||||||
|
"test-notion-bridge.yml",
|
||||||
|
"tianyan-daily-patrol.yml",
|
||||||
|
"tianyan-nightly-scan.yml",
|
||||||
|
"update-readme-bulletin.yml",
|
||||||
|
"update-readme.yml",
|
||||||
|
"update-repo-map.yml",
|
||||||
|
"zhuyuan-brain-sync.yml",
|
||||||
|
"zhuyuan-commander.yml",
|
||||||
|
"zhuyuan-daily-agent.yml",
|
||||||
|
"zhuyuan-daily-inspection.yml",
|
||||||
|
"zhuyuan-daily-selfcheck.yml",
|
||||||
|
"zhuyuan-exec-engine.yml",
|
||||||
|
"zhuyuan-gate-guard.yml",
|
||||||
|
"zhuyuan-issue-reply.yml",
|
||||||
|
"zhuyuan-pr-review.yml",
|
||||||
|
"zhuyuan-skyeye.yml"
|
||||||
|
],
|
||||||
|
"errors": []
|
||||||
|
},
|
||||||
|
"directory_scan": {
|
||||||
|
"checked": 19,
|
||||||
|
"present": 19,
|
||||||
|
"missing": []
|
||||||
|
},
|
||||||
|
"sub_repo_scan": {
|
||||||
|
"total": 2,
|
||||||
|
"verified": [
|
||||||
|
{
|
||||||
|
"name": "qinfendebingshuo/guanghulab",
|
||||||
|
"role": "main",
|
||||||
|
"guard_path_exists": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WENZHUOXI/guanghu-awen",
|
||||||
|
"role": "sub-repo",
|
||||||
|
"guard_path_exists": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ontology_scan": {
|
||||||
|
"dimension": "D16",
|
||||||
|
"name": "本体论完整性",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"item": "ontology.json 存在",
|
||||||
|
"status": "✅",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "核心公理完整性",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "6/6 条公理"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "三层安全定义",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "3/3 层"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "copilot-instructions 本体论宣言",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "已注入"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "README 本体论标识",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "已注入"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"neural_map_scan": {
|
||||||
|
"dimension": "D20",
|
||||||
|
"name": "双端映射完整性",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"item": "neural-map.json 存在且可解析",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "version: 3.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "映射 Workflow 文件检查",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "11/11 文件存在"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "未映射 Workflow 检查",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "85 个未映射(非核心 Workflow 可不映射,已映射 11 个)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "Brain 注册完整性",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "所有 Brain 均已注册"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "报告目录存在性",
|
||||||
|
"status": "✅",
|
||||||
|
"detail": "所有报告目录已创建"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unmapped_workflows": [
|
||||||
|
"agent-checkin.yml",
|
||||||
|
"auto-deploy-drive-bridge.yml",
|
||||||
|
"auto-reply-discussions.yml",
|
||||||
|
"bingshuo-deploy-agent.yml",
|
||||||
|
"bingshuo-neural-system.yml",
|
||||||
|
"brain-sync.yml",
|
||||||
|
"bridge-broadcast-pdf.yml",
|
||||||
|
"bridge-changes-to-notion.yml",
|
||||||
|
"bridge-heartbeat.yml",
|
||||||
|
"bridge-session-summary.yml",
|
||||||
|
"bridge-syslog-intake.yml",
|
||||||
|
"bridge-syslog-to-notion.yml",
|
||||||
|
"buffer-collect.yml",
|
||||||
|
"buffer-flush.yml",
|
||||||
|
"check-structure.yml",
|
||||||
|
"check-token-health.yml",
|
||||||
|
"daily-maintenance.yml",
|
||||||
|
"daily-report.yml",
|
||||||
|
"deploy-pages.yml",
|
||||||
|
"esp-signal-processor.yml",
|
||||||
|
"execution-sync.yml",
|
||||||
|
"federation-bridge.yml",
|
||||||
|
"feishu-syslog-bridge.yml",
|
||||||
|
"generate-module-doc.yml",
|
||||||
|
"grid-db-archive.yml",
|
||||||
|
"grid-db-processor.yml",
|
||||||
|
"grid-db-training-extract.yml",
|
||||||
|
"hli-contract-check.yml",
|
||||||
|
"merge-watchdog.yml",
|
||||||
|
"meta-watchdog.yml",
|
||||||
|
"multi-persona-awakening.yml",
|
||||||
|
"notion-callback-pipeline.yml",
|
||||||
|
"notion-connectivity-test.yml",
|
||||||
|
"notion-heartbeat.yml",
|
||||||
|
"notion-page-reader.yml",
|
||||||
|
"notion-poll.yml",
|
||||||
|
"notion-wake-listener.yml",
|
||||||
|
"openclaw-wake-loop.yml",
|
||||||
|
"persona-invoke.yml",
|
||||||
|
"persona-thinking-window.yml",
|
||||||
|
"pm2-server-diagnose.yml",
|
||||||
|
"process-notion-orders.yml",
|
||||||
|
"ps-on-build.yml",
|
||||||
|
"ps-on-chat.yml",
|
||||||
|
"ps-on-complete.yml",
|
||||||
|
"ps-on-login.yml",
|
||||||
|
"psp-daily-inspection.yml",
|
||||||
|
"pull-sync-awen.yml",
|
||||||
|
"push-broadcast-feishu.yml",
|
||||||
|
"push-broadcast.yml",
|
||||||
|
"readme-ui-refresh.yml",
|
||||||
|
"receive-spoke-checkin.yml",
|
||||||
|
"receive-syslog.yml",
|
||||||
|
"renew-gdrive-tokens.yml",
|
||||||
|
"sandbox-deploy.yml",
|
||||||
|
"skyeye-checkin-audit.yml",
|
||||||
|
"skyeye-checkin-receiver.yml",
|
||||||
|
"skyeye-credential-audit.yml",
|
||||||
|
"skyeye-daily-hibernation.yml",
|
||||||
|
"skyeye-devsync-repair.yml",
|
||||||
|
"skyeye-weekly-hibernation.yml",
|
||||||
|
"staging-preview.yml",
|
||||||
|
"sync-deploy-to-notion.yml",
|
||||||
|
"sync-griddb-to-drive.yml",
|
||||||
|
"sync-griddb-to-notion.yml",
|
||||||
|
"sync-login-entry.yml",
|
||||||
|
"sync-notion-profiles.yml",
|
||||||
|
"sync-notion-to-griddb.yml",
|
||||||
|
"sync-persona-studio.yml",
|
||||||
|
"sync-repo-to-drive.yml",
|
||||||
|
"syslog-auto-pipeline.yml",
|
||||||
|
"syslog-issue-pipeline.yml",
|
||||||
|
"tcs-semantic-landing.yml",
|
||||||
|
"test-notion-bridge.yml",
|
||||||
|
"tianyan-daily-patrol.yml",
|
||||||
|
"tianyan-nightly-scan.yml",
|
||||||
|
"update-readme-bulletin.yml",
|
||||||
|
"update-readme.yml",
|
||||||
|
"update-repo-map.yml",
|
||||||
|
"zhuyuan-brain-sync.yml",
|
||||||
|
"zhuyuan-commander.yml",
|
||||||
|
"zhuyuan-daily-agent.yml",
|
||||||
|
"zhuyuan-daily-inspection.yml",
|
||||||
|
"zhuyuan-issue-reply.yml",
|
||||||
|
"zhuyuan-pr-review.yml"
|
||||||
|
],
|
||||||
|
"invalid_brains": []
|
||||||
|
},
|
||||||
|
"issues": [
|
||||||
|
{
|
||||||
|
"severity": "warning",
|
||||||
|
"category": "guard_config",
|
||||||
|
"detail": "Guard web-deploy-guard.json missing fields: quota_policy"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": {
|
||||||
|
"total_issues": 1,
|
||||||
|
"errors": 0,
|
||||||
|
"warnings": 1,
|
||||||
|
"guards_healthy": "5/6",
|
||||||
|
"workflows_found": 96,
|
||||||
|
"directories_ok": "19/19"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"version": "3.0.0",
|
||||||
|
"description": "天眼 Notion 大脑 · 日报分析规则",
|
||||||
|
"created_by": "ZY-NEURAL-UPGRADE-2026-0325-R2-002",
|
||||||
|
"copyright": "国作登字-2026-A-00037559 · TCS-0002∞ 冰朔",
|
||||||
|
|
||||||
|
"severity_rules": {
|
||||||
|
"P0_immediate": {
|
||||||
|
"description": "立即处理 · 系统不可用级",
|
||||||
|
"conditions": [
|
||||||
|
{ "field": "overall_health", "operator": "equals", "value": "🔴" },
|
||||||
|
{ "field": "workflow_summary.failure", "operator": "greater_than_percent", "value": 20, "of": "workflow_summary.total_runs_24h" },
|
||||||
|
{ "field": "guard_status.active", "operator": "equals", "value": 0 },
|
||||||
|
{ "field": "skyeye_status.overall_health", "operator": "equals", "value": "🔴" }
|
||||||
|
],
|
||||||
|
"action": "generate_p0_work_order",
|
||||||
|
"notify": ["冰朔", "霜砚"],
|
||||||
|
"timeout_hours": 2
|
||||||
|
},
|
||||||
|
"P1_urgent": {
|
||||||
|
"description": "紧急 · 功能受损级",
|
||||||
|
"conditions": [
|
||||||
|
{ "field": "overall_health", "operator": "equals", "value": "🟡" },
|
||||||
|
{ "field": "guard_status.suspended", "operator": "greater_than", "value": 0 },
|
||||||
|
{ "field": "unmapped_workflows", "operator": "not_empty" },
|
||||||
|
{ "field": "quota_status", "operator": "contains", "value": "warning" }
|
||||||
|
],
|
||||||
|
"action": "generate_p1_work_order",
|
||||||
|
"notify": ["霜砚"],
|
||||||
|
"timeout_hours": 24
|
||||||
|
},
|
||||||
|
"P2_optimize": {
|
||||||
|
"description": "优化 · 非紧急改进",
|
||||||
|
"conditions": [
|
||||||
|
{ "field": "workflow_summary.cancelled", "operator": "greater_than", "value": 3 },
|
||||||
|
{ "field": "brain_summary.*.no_data", "operator": "greater_than", "value": 0 }
|
||||||
|
],
|
||||||
|
"action": "generate_p2_work_order",
|
||||||
|
"notify": [],
|
||||||
|
"timeout_hours": 72
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"trend_detection": {
|
||||||
|
"lookback_days": 7,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "failure_rate_rising",
|
||||||
|
"description": "失败率连续上升",
|
||||||
|
"condition": "连续 3 天 failure_rate_percent 递增",
|
||||||
|
"severity": "P1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "workflow_going_silent",
|
||||||
|
"description": "某 Workflow 连续无运行记录",
|
||||||
|
"condition": "某 workflow 连续 3 天 runs = 0",
|
||||||
|
"severity": "P1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "guard_flapping",
|
||||||
|
"description": "Guard 反复 active/suspended",
|
||||||
|
"condition": "同一 Guard 7天内状态切换 > 3 次",
|
||||||
|
"severity": "P2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quota_approaching_limit",
|
||||||
|
"description": "配额逼近上限",
|
||||||
|
"condition": "任一资源 usage/limit > 80%",
|
||||||
|
"severity": "P1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"auto_heal_rules": {
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "retry_failed_workflow",
|
||||||
|
"condition": "单个 Workflow 失败 1 次且非 P0",
|
||||||
|
"action": "generate_retry_command",
|
||||||
|
"max_retries": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clean_old_reports",
|
||||||
|
"condition": "neural-reports/ 下超过 7 天的报告文件",
|
||||||
|
"action": "generate_cleanup_command"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "restart_suspended_guard",
|
||||||
|
"condition": "Guard suspended 且当前配额已恢复",
|
||||||
|
"action": "generate_guard_restart_command"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
{
|
||||||
|
"version": "3.0.0",
|
||||||
|
"created": "2026-03-25",
|
||||||
|
"created_by": "ZY-NEURAL-UPGRADE-2026-0325-R2-001",
|
||||||
|
"description": "Notion↔GitHub 双端 Agent 映射表",
|
||||||
|
"copyright": "国作登字-2026-A-00037559 · TCS-0002∞ 冰朔",
|
||||||
|
|
||||||
|
"notion_brains": {
|
||||||
|
"AG-TY-01": {
|
||||||
|
"name": "天眼 Notion 大脑",
|
||||||
|
"role": "总控中枢",
|
||||||
|
"managed_workflows": [
|
||||||
|
"zhuyuan-skyeye",
|
||||||
|
"skyeye-weekly-scan",
|
||||||
|
"server-patrol",
|
||||||
|
"zhuyuan-daily-selfcheck",
|
||||||
|
"neural-daily-digest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AG-SY-01": {
|
||||||
|
"name": "霜砚",
|
||||||
|
"role": "Notion 执行体 · 指令签发",
|
||||||
|
"managed_workflows": [
|
||||||
|
"zhuyuan-gate-guard",
|
||||||
|
"deploy-to-server",
|
||||||
|
"zhuyuan-exec-engine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SY-03": {
|
||||||
|
"name": "运营巡检 Agent",
|
||||||
|
"role": "运营层巡检",
|
||||||
|
"managed_workflows": [
|
||||||
|
"syslog-pipeline",
|
||||||
|
"distribute-broadcasts",
|
||||||
|
"sync-dev-status"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"SY-02": {
|
||||||
|
"name": "结构快照 Agent",
|
||||||
|
"role": "Notion 结构快照",
|
||||||
|
"managed_workflows": []
|
||||||
|
},
|
||||||
|
"SY-01": {
|
||||||
|
"name": "工单引擎 Agent",
|
||||||
|
"role": "工单处理",
|
||||||
|
"managed_workflows": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"github_workflows": {
|
||||||
|
"zhuyuan-skyeye": {
|
||||||
|
"file": ".github/workflows/zhuyuan-skyeye.yml",
|
||||||
|
"name": "天眼主引擎",
|
||||||
|
"trigger": "cron 06:00 CST + workflow_dispatch",
|
||||||
|
"brain": "AG-TY-01",
|
||||||
|
"report_path": "data/neural-reports/skyeye/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"skyeye-weekly-scan": {
|
||||||
|
"file": ".github/workflows/skyeye-weekly-scan.yml",
|
||||||
|
"name": "周六大巡检",
|
||||||
|
"trigger": "cron 周六 20:00 CST",
|
||||||
|
"brain": "AG-TY-01",
|
||||||
|
"report_path": "data/neural-reports/weekly-scan/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"zhuyuan-gate-guard": {
|
||||||
|
"file": ".github/workflows/zhuyuan-gate-guard.yml",
|
||||||
|
"name": "智能门禁",
|
||||||
|
"trigger": "push",
|
||||||
|
"brain": "AG-SY-01",
|
||||||
|
"report_path": "data/neural-reports/gate-guard/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"deploy-to-server": {
|
||||||
|
"file": ".github/workflows/deploy-to-server.yml",
|
||||||
|
"name": "CD 自动部署",
|
||||||
|
"trigger": "push main",
|
||||||
|
"brain": "AG-SY-01",
|
||||||
|
"report_path": "data/neural-reports/cd-deploy/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"syslog-pipeline": {
|
||||||
|
"file": ".github/workflows/syslog-pipeline.yml",
|
||||||
|
"name": "SYSLOG 处理",
|
||||||
|
"trigger": "push (syslog路径)",
|
||||||
|
"brain": "SY-03",
|
||||||
|
"report_path": "data/neural-reports/syslog/",
|
||||||
|
"priority": "P1"
|
||||||
|
},
|
||||||
|
"distribute-broadcasts": {
|
||||||
|
"file": ".github/workflows/distribute-broadcasts.yml",
|
||||||
|
"name": "广播分发",
|
||||||
|
"trigger": "push (broadcast路径)",
|
||||||
|
"brain": "SY-03",
|
||||||
|
"report_path": "data/neural-reports/broadcast/",
|
||||||
|
"priority": "P1"
|
||||||
|
},
|
||||||
|
"server-patrol": {
|
||||||
|
"file": ".github/workflows/server-patrol.yml",
|
||||||
|
"name": "服务器巡检",
|
||||||
|
"trigger": "cron 08:00 + 20:00 CST",
|
||||||
|
"brain": "AG-TY-01",
|
||||||
|
"report_path": "data/neural-reports/server-patrol/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"zhuyuan-daily-selfcheck": {
|
||||||
|
"file": ".github/workflows/zhuyuan-daily-selfcheck.yml",
|
||||||
|
"name": "核心大脑自检",
|
||||||
|
"trigger": "cron 08:00 CST",
|
||||||
|
"brain": "AG-TY-01",
|
||||||
|
"report_path": "data/neural-reports/brain-check/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"sync-dev-status": {
|
||||||
|
"file": ".github/workflows/sync-dev-status.yml",
|
||||||
|
"name": "开发者状态同步",
|
||||||
|
"trigger": "cron 09:00 + 22:00 CST",
|
||||||
|
"brain": "SY-03",
|
||||||
|
"report_path": "data/neural-reports/dev-status/",
|
||||||
|
"priority": "P1"
|
||||||
|
},
|
||||||
|
"zhuyuan-exec-engine": {
|
||||||
|
"file": ".github/workflows/zhuyuan-exec-engine.yml",
|
||||||
|
"name": "远程执行引擎",
|
||||||
|
"trigger": "issue labeled zhuyuan-exec",
|
||||||
|
"brain": "AG-SY-01",
|
||||||
|
"report_path": "data/neural-reports/exec-engine/",
|
||||||
|
"priority": "P0"
|
||||||
|
},
|
||||||
|
"neural-daily-digest": {
|
||||||
|
"file": ".github/workflows/neural-daily-digest.yml",
|
||||||
|
"name": "汇总引擎",
|
||||||
|
"trigger": "cron 21:00 CST",
|
||||||
|
"brain": "AG-TY-01",
|
||||||
|
"report_path": "data/neural-reports/daily-digest/",
|
||||||
|
"priority": "P0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"unmapped_workflows": [],
|
||||||
|
|
||||||
|
"validation_rules": {
|
||||||
|
"every_workflow_must_have_brain": true,
|
||||||
|
"every_workflow_must_have_report_path": true,
|
||||||
|
"no_duplicate_brain_assignment": false,
|
||||||
|
"orphan_check_frequency": "daily"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -202,6 +202,131 @@ function checkOntologyIntegrity() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// D20 · 双端映射完整性检查 (Neural Map Integrity)
|
||||||
|
function checkNeuralMapIntegrity() {
|
||||||
|
var result = {
|
||||||
|
dimension: 'D20',
|
||||||
|
name: '双端映射完整性',
|
||||||
|
checks: [],
|
||||||
|
unmapped_workflows: [],
|
||||||
|
invalid_brains: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var neuralMapPath = path.join(SKYEYE_DIR, 'neural-map.json');
|
||||||
|
if (!fs.existsSync(neuralMapPath)) {
|
||||||
|
result.checks.push({
|
||||||
|
item: 'neural-map.json 存在',
|
||||||
|
status: '🔴',
|
||||||
|
detail: '文件缺失'
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var neuralMap = loadJSON(neuralMapPath);
|
||||||
|
if (!neuralMap) {
|
||||||
|
result.checks.push({
|
||||||
|
item: 'neural-map.json 可解析',
|
||||||
|
status: '🔴',
|
||||||
|
detail: 'JSON 解析失败'
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.checks.push({
|
||||||
|
item: 'neural-map.json 存在且可解析',
|
||||||
|
status: '✅',
|
||||||
|
detail: 'version: ' + (neuralMap.version || 'unknown')
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查所有映射的 Workflow 文件是否实际存在
|
||||||
|
var mappedFiles = {};
|
||||||
|
var workflowEntries = Object.entries(neuralMap.github_workflows || {});
|
||||||
|
var existCount = 0;
|
||||||
|
var missingCount = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < workflowEntries.length; i++) {
|
||||||
|
var wfId = workflowEntries[i][0];
|
||||||
|
var wf = workflowEntries[i][1];
|
||||||
|
var filePath = path.join(ROOT, wf.file);
|
||||||
|
mappedFiles[wf.file] = true;
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
existCount++;
|
||||||
|
} else {
|
||||||
|
missingCount++;
|
||||||
|
result.checks.push({
|
||||||
|
item: '映射文件存在: ' + wf.file,
|
||||||
|
status: '🔴',
|
||||||
|
detail: wfId + ' 映射的文件不存在'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.checks.push({
|
||||||
|
item: '映射 Workflow 文件检查',
|
||||||
|
status: missingCount === 0 ? '✅' : '🔴',
|
||||||
|
detail: existCount + '/' + workflowEntries.length + ' 文件存在'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查实际 .yml 中是否有未映射的(仅检查核心 Workflow,非全量)
|
||||||
|
var workflowDir = path.join(ROOT, '.github/workflows');
|
||||||
|
if (fs.existsSync(workflowDir)) {
|
||||||
|
var actualFiles = fs.readdirSync(workflowDir)
|
||||||
|
.filter(function(f) { return f.endsWith('.yml') || f.endsWith('.yaml'); });
|
||||||
|
|
||||||
|
for (var j = 0; j < actualFiles.length; j++) {
|
||||||
|
var ymlPath = '.github/workflows/' + actualFiles[j];
|
||||||
|
if (!mappedFiles[ymlPath]) {
|
||||||
|
result.unmapped_workflows.push(actualFiles[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: unmapped is not necessarily an error since neural-map only maps core workflows
|
||||||
|
// The total workflow count minus mapped workflows gives the expected unmapped count
|
||||||
|
var mappedCount = workflowEntries.length;
|
||||||
|
result.checks.push({
|
||||||
|
item: '未映射 Workflow 检查',
|
||||||
|
status: '✅',
|
||||||
|
detail: result.unmapped_workflows.length + ' 个未映射(非核心 Workflow 可不映射,已映射 ' + mappedCount + ' 个)'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查每个 brain 是否在 notion_brains 中注册
|
||||||
|
for (var k = 0; k < workflowEntries.length; k++) {
|
||||||
|
var wfId2 = workflowEntries[k][0];
|
||||||
|
var wf2 = workflowEntries[k][1];
|
||||||
|
if (wf2.brain && !(neuralMap.notion_brains || {})[wf2.brain]) {
|
||||||
|
result.invalid_brains.push({ workflow: wfId2, brain: wf2.brain });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.checks.push({
|
||||||
|
item: 'Brain 注册完整性',
|
||||||
|
status: result.invalid_brains.length === 0 ? '✅' : '🔴',
|
||||||
|
detail: result.invalid_brains.length === 0
|
||||||
|
? '所有 Brain 均已注册'
|
||||||
|
: result.invalid_brains.length + ' 个 Brain 未注册'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查 report_path 目录是否存在
|
||||||
|
var reportPathMissing = 0;
|
||||||
|
for (var m = 0; m < workflowEntries.length; m++) {
|
||||||
|
var wf3 = workflowEntries[m][1];
|
||||||
|
if (wf3.report_path && !fs.existsSync(path.join(ROOT, wf3.report_path))) {
|
||||||
|
reportPathMissing++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.checks.push({
|
||||||
|
item: '报告目录存在性',
|
||||||
|
status: reportPathMissing === 0 ? '✅' : '🟡',
|
||||||
|
detail: reportPathMissing === 0
|
||||||
|
? '所有报告目录已创建'
|
||||||
|
: reportPathMissing + ' 个报告目录缺失'
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const mode = args.find(a => a.startsWith('--mode='))?.split('=')[1] || 'full';
|
const mode = args.find(a => a.startsWith('--mode='))?.split('=')[1] || 'full';
|
||||||
|
|
@ -224,6 +349,7 @@ function run() {
|
||||||
directory_scan: scanDirectoryStructure(),
|
directory_scan: scanDirectoryStructure(),
|
||||||
sub_repo_scan: scanSubRepos(manifest),
|
sub_repo_scan: scanSubRepos(manifest),
|
||||||
ontology_scan: checkOntologyIntegrity(),
|
ontology_scan: checkOntologyIntegrity(),
|
||||||
|
neural_map_scan: checkNeuralMapIntegrity(),
|
||||||
issues: [],
|
issues: [],
|
||||||
summary: {}
|
summary: {}
|
||||||
};
|
};
|
||||||
|
|
@ -270,6 +396,32 @@ function run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// D20 · 双端映射完整性 issues
|
||||||
|
if (scanResult.neural_map_scan && scanResult.neural_map_scan.checks) {
|
||||||
|
for (const check of scanResult.neural_map_scan.checks) {
|
||||||
|
if (check.status === '🔴') {
|
||||||
|
scanResult.issues.push({
|
||||||
|
severity: 'error',
|
||||||
|
category: 'neural_map_integrity',
|
||||||
|
detail: `D20 · ${check.item}: ${check.detail || '失败'}`
|
||||||
|
});
|
||||||
|
} else if (check.status === '🟡') {
|
||||||
|
scanResult.issues.push({
|
||||||
|
severity: 'warning',
|
||||||
|
category: 'neural_map_integrity',
|
||||||
|
detail: `D20 · ${check.item}: ${check.detail || '需关注'}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scanResult.neural_map_scan.invalid_brains.length > 0) {
|
||||||
|
scanResult.issues.push({
|
||||||
|
severity: 'error',
|
||||||
|
category: 'neural_map_integrity',
|
||||||
|
detail: `D20 · Brain 映射指向不存在的 Agent: ${scanResult.neural_map_scan.invalid_brains.map(b => b.brain).join(', ')}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Summary
|
// Summary
|
||||||
scanResult.summary = {
|
scanResult.summary = {
|
||||||
total_issues: scanResult.issues.length,
|
total_issues: scanResult.issues.length,
|
||||||
|
|
@ -304,6 +456,14 @@ function run() {
|
||||||
console.log(` ${check.status} ${check.item}${check.detail ? ' · ' + check.detail : ''}${check.version ? ' · v' + check.version : ''}`);
|
console.log(` ${check.status} ${check.item}${check.detail ? ' · ' + check.detail : ''}${check.version ? ' · v' + check.version : ''}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// D20 · 双端映射完整性状态
|
||||||
|
if (scanResult.neural_map_scan) {
|
||||||
|
console.log(`[SkyEye Scan Engine] D20 Neural Map:`);
|
||||||
|
for (const check of scanResult.neural_map_scan.checks) {
|
||||||
|
console.log(` ${check.status} ${check.item}${check.detail ? ' · ' + check.detail : ''}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
console.log(`[SkyEye Scan Engine] Log saved: ${logPath}`);
|
console.log(`[SkyEye Scan Engine] Log saved: ${logPath}`);
|
||||||
|
|
||||||
// Output full result as JSON for pipeline
|
// Output full result as JSON for pipeline
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue