🔗 AOAC Agent Chain v1.0 · 环环相扣Agent链路闭环系统

Phase 0: 密钥修复
- workflow中ZY_ZHIPU→ZY_QINGYAN, ZY_QWEN→ZY_QIANWEN
- secrets-manifest新增11个缺失密钥(ZY_BRAIN_*·AWEN_*·ZY_SVR_SV_*·ZHUYUAN_API_KEY)
- 迁移映射添加COS_SECRET_ID/KEY→ZY_OSS_KEY/SECRET

Phase 1-4: AOAC系统完整实现
- 8个Agent脚本: scripts/aoac/{dev-sentinel,merge-sentinel,chain-fusion,readme-sync-module,readme-master-agent,notion-sync-signal,chain-repair-agent,repair-supervisor}.js
- 4个workflow: aoac-{copilot-sentinel,merge-sentinel,readme-master,chain-repair}.yml
- 数据目录: data/aoac/ + chain-status.json

Phase 5: HLDP协议扩展
- msg_type新增chain类型(v3.0.2)
- 7个chain intent: chain_awake/half_ready/fusion/trigger/repair/verdict/alert

Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/2c37ba8a-8fe8-4d88-aa5a-2783f65e1266

Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-11 05:50:00 +00:00 committed by GitHub
parent 2f5b0ce09b
commit f51dd50cf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 2334 additions and 14 deletions

93
.github/workflows/aoac-chain-repair.yml vendored Normal file
View File

@ -0,0 +1,93 @@
# ═══════════════════════════════════════════════════
# AOAC-07+08 · 链路修复Agent + 监督Agent
# AGE OS Agent Chain · 异常检测+自动修复+监督判定
# 唤醒条件1每天23:30 CST检查回执时间
# 唤醒条件2手动触发workflow_dispatch
# 版权:国作登字-2026-A-00037559 · TCS-0002∞
# ═══════════════════════════════════════════════════
name: 🔧 AOAC-07+08 · 修复+监督
on:
schedule:
- cron: '30 15 * * *' # UTC 15:30 = 北京 23:30
workflow_dispatch:
inputs:
force_repair:
description: '强制执行修复'
type: boolean
default: false
permissions:
contents: write
issues: write
concurrency:
group: aoac-chain-repair
cancel-in-progress: false
jobs:
# ────────── AOAC-07 · 修复Agent ──────────
repair-agent:
name: 🔧 AOAC-07 · 链路修复
runs-on: ubuntu-latest
outputs:
repair_result: ${{ steps.repair.outputs.repair_result }}
needed_repair: ${{ steps.repair.outputs.needed_repair }}
repair_id: ${{ steps.repair.outputs.repair_id }}
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🔧 执行链路修复Agent
id: repair
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ZY_NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
ZY_NOTION_RECEIPT_DB: ${{ secrets.ZY_NOTION_RECEIPT_DB }}
run: node scripts/aoac/chain-repair-agent.js
- name: 💾 提交修复报告
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/
if ! git diff --cached --quiet; then
git commit -m "🔧 AOAC-07 · 修复报告 · ${{ steps.repair.outputs.repair_id || 'check' }} [skip ci]"
git push
fi
# ────────── AOAC-08 · 监督Agent ──────────
supervisor:
name: 👁️ AOAC-08 · 修复监督
needs: repair-agent
if: always()
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout (最新)
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: 👁️ 执行监督Agent
id: supervisor
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ZY_NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
ZY_NOTION_RECEIPT_DB: ${{ secrets.ZY_NOTION_RECEIPT_DB }}
ZY_SMTP_USER: ${{ secrets.ZY_SMTP_USER }}
ZY_SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }}
run: node scripts/aoac/repair-supervisor.js
- name: 💾 提交监督判定
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/
if ! git diff --cached --quiet; then
git commit -m "👁️ AOAC-08 · 监督判定 · ${{ steps.supervisor.outputs.verdict || 'check' }} [skip ci]"
git push
fi

View File

@ -0,0 +1,52 @@
# ═══════════════════════════════════════════════════
# AOAC-01 · 副驾驶哨兵 (Copilot Dev Sentinel)
# AGE OS Agent Chain · 半Agent开发侧
# 唤醒条件PR创建/更新时触发
# 版权:国作登字-2026-A-00037559 · TCS-0002∞
# ═══════════════════════════════════════════════════
name: 🔭 AOAC-01 · 副驾驶哨兵
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [main]
permissions:
contents: write
pull-requests: read
concurrency:
group: aoac-copilot-sentinel-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
dev-sentinel:
name: 🔭 AOAC-01 · 开发感知
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🔭 执行副驾驶哨兵
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
EVENT_NAME: ${{ github.event_name }}
run: node scripts/aoac/dev-sentinel.js
- name: 💾 提交开发日志
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/dev-session-log.json data/aoac/chain-status.json
if ! git diff --cached --quiet; then
git commit -m "🔭 AOAC-01 · PR #${{ github.event.pull_request.number }} 开发日志 [skip ci]"
git push
fi

View File

@ -0,0 +1,85 @@
# ═══════════════════════════════════════════════════
# AOAC-02+03 · 合并哨兵 + 合体引擎
# AGE OS Agent Chain · PR合并后的CI收集与链路融合
# 唤醒条件PR合并到main
# 版权:国作登字-2026-A-00037559 · TCS-0002∞
# ═══════════════════════════════════════════════════
name: 🔍 AOAC-02+03 · 合并哨兵+合体
on:
pull_request:
types: [closed]
branches: [main]
permissions:
contents: write
pull-requests: read
checks: read
statuses: read
concurrency:
group: aoac-merge-sentinel
cancel-in-progress: false
jobs:
# ────────── AOAC-02 · 合并哨兵 ──────────
merge-sentinel:
name: 🔍 AOAC-02 · CI收集
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
outputs:
ci_result: ${{ steps.sentinel.outputs.ci_result }}
ready_for_fusion: ${{ steps.sentinel.outputs.ready_for_fusion }}
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 🔍 执行合并哨兵
id: sentinel
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
BASE_BRANCH: ${{ github.event.pull_request.base.ref }}
run: node scripts/aoac/merge-sentinel.js
- name: 💾 提交合并日志
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/merge-result-log.json data/aoac/chain-status.json
if ! git diff --cached --quiet; then
git commit -m "🔍 AOAC-02 · PR #${{ github.event.pull_request.number }} 合并CI日志 [skip ci]"
git push
fi
# ────────── AOAC-03 · 合体引擎 ──────────
chain-fusion:
name: ⚡ AOAC-03 · 合体引擎
needs: merge-sentinel
if: always() && needs.merge-sentinel.result == 'success'
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout (最新)
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: ⚡ 执行合体引擎
run: node scripts/aoac/chain-fusion.js
- name: 💾 提交链路报告+触发信号
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/
if ! git diff --cached --quiet; then
git commit -m "⚡ AOAC-03 · 链路合体报告 · PR #${{ github.event.pull_request.number }} [skip ci]"
git push
fi

140
.github/workflows/aoac-readme-master.yml vendored Normal file
View File

@ -0,0 +1,140 @@
# ═══════════════════════════════════════════════════
# AOAC-04+05+06 · 首页同步模块 + 主控Agent + Notion信号
# AGE OS Agent Chain · 事件触发 + 时间触发双路径
# 唤醒条件1data/aoac/readme-sync-trigger.json 被写入(事件)
# 唤醒条件2每天23:00 CST = UTC 15:00时间
# 版权:国作登字-2026-A-00037559 · TCS-0002∞
# ═══════════════════════════════════════════════════
name: 🏠 AOAC-04+05+06 · 首页主控+Notion同步
on:
push:
branches: [main]
paths:
- 'data/aoac/readme-sync-trigger.json'
- 'data/aoac/chain-report.json'
schedule:
- cron: '0 15 * * *' # UTC 15:00 = 北京 23:00
workflow_dispatch:
inputs:
mode:
description: '运行模式'
type: choice
options:
- auto
- event
- scheduled
default: auto
permissions:
contents: write
concurrency:
group: aoac-readme-master
cancel-in-progress: false
jobs:
# ────────── AOAC-04 · 同步模块 ──────────
sync-module:
name: 📋 AOAC-04 · 同步模块
runs-on: ubuntu-latest
outputs:
has_payload: ${{ steps.sync.outputs.has_payload }}
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 📋 执行同步模块
id: sync
run: |
node scripts/aoac/readme-sync-module.js
if [ -f "data/aoac/readme-update-payload.json" ]; then
echo "has_payload=true" >> "$GITHUB_OUTPUT"
else
echo "has_payload=false" >> "$GITHUB_OUTPUT"
fi
- name: 💾 提交更新数据
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/
if ! git diff --cached --quiet; then
git commit -m "📋 AOAC-04 · 同步模块数据更新 [skip ci]"
git push
fi
# ────────── AOAC-05 · 首页主控Agent ──────────
master-update:
name: 🏠 AOAC-05 · 首页主控
needs: sync-module
if: always()
runs-on: ubuntu-latest
outputs:
master_report_id: ${{ steps.master.outputs.master_report_id }}
readme_updated: ${{ steps.master.outputs.readme_updated }}
changes_summary: ${{ steps.master.outputs.changes_summary }}
steps:
- name: 📥 Checkout (最新)
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: 🏠 执行首页主控Agent
id: master
env:
ZY_LLM_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
ZY_LLM_BASE_URL: ${{ secrets.ZY_LLM_BASE_URL }}
run: |
MODE="${{ github.event_name == 'schedule' && 'scheduled' || github.event.inputs.mode || 'event' }}"
node scripts/aoac/readme-master-agent.js "$MODE"
- name: 📊 同步调用仪表盘生成器
run: |
if [ -f "scripts/generate-readme-dashboard.js" ]; then
node scripts/generate-readme-dashboard.js || true
fi
- name: 💾 提交README更新
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add README.md data/aoac/ data/bulletin-board/ .github/persona-brain/memory.json
if ! git diff --cached --quiet; then
git commit -m "🏠 AOAC-05 · 首页主控更新 · $(date -u '+%Y-%m-%d %H:%M') [skip ci]"
git push
fi
# ────────── AOAC-06 · Notion同步信号 ──────────
notion-sync:
name: 📡 AOAC-06 · Notion同步
needs: master-update
if: always() && needs.master-update.result == 'success'
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout (最新)
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: 📡 发送Notion同步信号
id: notion
env:
ZY_NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
ZY_NOTION_RECEIPT_DB: ${{ secrets.ZY_NOTION_RECEIPT_DB }}
run: node scripts/aoac/notion-sync-signal.js
- name: 💾 提交同步日志
run: |
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/aoac/
if ! git diff --cached --quiet; then
git commit -m "📡 AOAC-06 · Notion同步信号已发送 [skip ci]"
git push
fi

View File

@ -104,8 +104,8 @@ jobs:
ZY_OSS_SECRET: ${{ secrets.ZY_OSS_SECRET }}
ZY_COS_REGION: ${{ secrets.ZY_COS_REGION }}
ZY_DEEPSEEK_API_KEY: ${{ secrets.ZY_DEEPSEEK_API_KEY }}
ZY_ZHIPU_API_KEY: ${{ secrets.ZY_ZHIPU_API_KEY }}
ZY_QWEN_API_KEY: ${{ secrets.ZY_QWEN_API_KEY }}
ZY_QINGYAN_API_KEY: ${{ secrets.ZY_QINGYAN_API_KEY }}
ZY_QIANWEN_API_KEY: ${{ secrets.ZY_QIANWEN_API_KEY }}
ZY_KIMI_API_KEY: ${{ secrets.ZY_KIMI_API_KEY }}
run: |
node scripts/cos-training-trigger.js \

View File

@ -468,11 +468,11 @@ COS存储共享池架构
# DeepSeek
ZY_DEEPSEEK_API_KEY=sk-xxx
# 智谱AI (GLM)
ZY_ZHIPU_API_KEY=xxx
# 智谱AI (GLM/清言)
ZY_QINGYAN_API_KEY=xxx
# 通义千问 (Qwen/DashScope)
ZY_QWEN_API_KEY=sk-xxx
ZY_QIANWEN_API_KEY=sk-xxx
# Kimi (Moonshot)
ZY_KIMI_API_KEY=sk-xxx

View File

@ -2,17 +2,18 @@
"_meta": {
"manifest_id": "ZY-SECRETS-MANIFEST-v2.0",
"created": "2026-03-29T10:43:00Z",
"updated": "2026-04-03T07:15:00Z",
"updated": "2026-04-11T05:30:00Z",
"created_by": "铸渊 · ICE-GL-ZY001",
"directive": "SY-CMD-KEY-012 · 密钥全量清理与统一替换 + 7 Notion Secret审计 + 国内服务器密钥扩展 + D45·AGE OS数据库+大模型+硅谷服务器密钥扩展",
"purpose": "铸渊仓库密钥主清单 — 冰朔配置密钥的唯一参考文档",
"naming_convention": "所有密钥统一使用 ZY_ 前缀 · 铸渊(Zhuyuan)自主命名体系",
"total_secrets": 58,
"required": 39,
"optional": 16,
"total_secrets": 69,
"required": 49,
"optional": 17,
"replaced_old_secrets": 59,
"reduction": "59 → 58 (新增13个AGE OS密钥)",
"v2_changes": "新增ZY_CN_SERVER_* 4个密钥用于广州国内服务器(ZY-SVR-003)"
"reduction": "59 → 69 (新增AOAC密钥审计·ZY_BRAIN_*·AWEN_*·ZY_SVR_SV_*·ZHUYUAN_API_KEY)",
"v2_changes": "新增ZY_CN_SERVER_* 4个密钥用于广州国内服务器(ZY-SVR-003)",
"v2_1_changes": "D64密钥审计新增ZY_BRAIN_*(大脑服务器3个)+AWEN_*(阿文代理3个)+ZY_SVR_SV_*(硅谷4个)+ZHUYUAN_API_KEY(MCP鉴权1个)·统一ZY_QWEN→ZY_QIANWEN·ZY_ZHIPU→ZY_QINGYAN"
},
"migration_mapping": {
"description": "旧密钥名称 → 新ZY_*名称 完整映射表",
@ -73,7 +74,12 @@
"GHAPP_PRIVATE_KEY": "ZY_GHAPP_KEY",
"PUSH_BROADCAST_TOKEN": "ZY_PUSH_TOKEN",
"OSS_ACCESS_KEY": "ZY_OSS_KEY",
"OSS_SECRET_KEY": "ZY_OSS_SECRET"
"OSS_SECRET_KEY": "ZY_OSS_SECRET",
"COS_SECRET_ID": "ZY_OSS_KEY",
"COS_SECRET_KEY": "ZY_OSS_SECRET",
"NOTION_TOKEN": "ZY_NOTION_TOKEN",
"ZY_ZHIPU_API_KEY": "ZY_QINGYAN_API_KEY",
"ZY_QWEN_API_KEY": "ZY_QIANWEN_API_KEY"
}
},
"secrets": {
@ -779,6 +785,149 @@
"replaces": [],
"used_by_workflows": [],
"note": "占位·暂不启用"
},
{
"id": 58,
"name": "ZY_BRAIN_HOST",
"category": "服务器 · 大脑服务器(ZY-SVR-005)",
"description": "大脑服务器IP/主机名 — PostgreSQL+MCP+订阅服务所在服务器",
"type": "hostname",
"example_format": "43.156.237.110",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "腾讯云轻量应用服务器·新加坡·43.156.237.110·与面孔服务器(ZY-SVR-002)互通·ping 0.77ms"
},
{
"id": 59,
"name": "ZY_BRAIN_USER",
"category": "服务器 · 大脑服务器(ZY-SVR-005)",
"description": "大脑服务器SSH登录用户名",
"type": "username",
"example_format": "root",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "大脑服务器SSH登录用户名"
},
{
"id": 60,
"name": "ZY_BRAIN_KEY",
"category": "服务器 · 大脑服务器(ZY-SVR-005)",
"description": "大脑服务器SSH私钥完整PEM格式",
"type": "ssh_private_key",
"example_format": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "⚠️ 关键密钥 · 大脑服务器SSH私钥·不同于ZY_SERVER_KEY(面孔服务器)"
},
{
"id": 61,
"name": "ZHUYUAN_API_KEY",
"category": "MCP · 鉴权",
"description": "铸渊MCP Server API鉴权密钥 — Bearer Token用于外部访问MCP Server",
"type": "api_key",
"example_format": "zy-mcp-xxxxxxxxxxxxxxxx",
"replaces": [],
"used_by_workflows": [
"deploy-to-zhuyuan-server.yml"
],
"note": "✅ 已配置(2026-04-07) · MCP Server端口3100·通过Bearer Token鉴权·health端点和loopback免鉴权"
},
{
"id": 62,
"name": "AWEN_DOMAIN",
"category": "Awen · 域名代理",
"description": "Awen域名 — 未备案域名通过新加坡Nginx反向代理到广州后端",
"type": "domain",
"example_format": "awen.example.com",
"replaces": [],
"used_by_workflows": [
"deploy-awen-domain-proxy.yml"
],
"note": "⚠️ 未配置 · 冰朔需在GitHub Secrets中配置Awen域名"
},
{
"id": 63,
"name": "AWEN_BACKEND_HOST",
"category": "Awen · 域名代理",
"description": "Awen后端服务器IP/主机名 — 广州服务器地址",
"type": "hostname",
"example_format": "43.139.xxx.xxx",
"replaces": [],
"used_by_workflows": [
"deploy-awen-domain-proxy.yml"
],
"note": "⚠️ 未配置 · Awen后端所在的广州服务器IP"
},
{
"id": 64,
"name": "AWEN_BACKEND_PORT",
"category": "Awen · 域名代理",
"description": "Awen后端服务端口 — 后端服务监听的端口号",
"type": "port",
"example_format": "3000",
"replaces": [],
"used_by_workflows": [
"deploy-awen-domain-proxy.yml"
],
"note": "⚠️ 未配置 · Awen后端服务监听的端口号"
},
{
"id": 65,
"name": "ZY_SVR_SV_HOST",
"category": "服务器 · 硅谷专线(ZY-SVR-SV)",
"description": "硅谷专线服务器IP地址 — Claude中继/Xray Reality节点",
"type": "hostname",
"example_format": "xxx.xxx.xxx.xxx",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "硅谷专线服务器·吱吱线·Claude中继"
},
{
"id": 66,
"name": "ZY_SVR_SV_PORT",
"category": "服务器 · 硅谷专线(ZY-SVR-SV)",
"description": "硅谷专线服务端口",
"type": "port",
"example_format": "443",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "硅谷专线服务端口"
},
{
"id": 67,
"name": "ZY_SVR_SV_REALITY_PUBLIC_KEY",
"category": "服务器 · 硅谷专线(ZY-SVR-SV)",
"description": "Xray Reality协议公钥",
"type": "public_key",
"example_format": "base64_encoded_key",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "Xray Reality协议公钥·用于客户端配置"
},
{
"id": 68,
"name": "ZY_SVR_SV_REALITY_SHORT_ID",
"category": "服务器 · 硅谷专线(ZY-SVR-SV)",
"description": "Xray Reality协议Short ID",
"type": "config",
"example_format": "hex_string",
"replaces": [],
"used_by_workflows": [
"infinity-evolution.yml"
],
"note": "Xray Reality协议Short ID·用于客户端配置"
}
],
"optional": [

0
data/aoac/.gitkeep Normal file
View File

View File

@ -0,0 +1,79 @@
{
"_meta": {
"system": "AGE OS Agent Chain (AOAC) v1.0",
"description": "环环相扣Agent链路闭环系统 · 全链路状态总览",
"created": "2026-04-11T05:30:00Z",
"created_by": "铸渊 · ICE-GL-ZY001",
"copyright": "国作登字-2026-A-00037559 · TCS-0002∞"
},
"agents": {
"AOAC-01": {
"name": "copilot-dev-sentinel",
"name_cn": "副驾驶哨兵",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "pull_request.opened|synchronize"
},
"AOAC-02": {
"name": "action-merge-sentinel",
"name_cn": "合并哨兵",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "pull_request.closed+merged"
},
"AOAC-03": {
"name": "dev-chain-agent",
"name_cn": "开发全链路Agent",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "AOAC-02.completed"
},
"AOAC-04": {
"name": "readme-sync-module",
"name_cn": "首页同步模块",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "data/aoac/readme-sync-trigger.json.written"
},
"AOAC-05": {
"name": "readme-master-agent",
"name_cn": "首页主控Agent",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "event+schedule(23:00 CST)"
},
"AOAC-06": {
"name": "notion-sync-signal",
"name_cn": "Notion同步信号",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "AOAC-05.completed"
},
"AOAC-07": {
"name": "chain-repair-agent",
"name_cn": "链路修复Agent",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "receipt_db.red|schedule(23:30 CST)"
},
"AOAC-08": {
"name": "repair-supervisor",
"name_cn": "修复监督Agent",
"status": "idle",
"last_run": null,
"last_success": null,
"trigger": "AOAC-07.started"
}
},
"chain_health": "unknown",
"last_full_cycle": null,
"total_cycles": 0,
"total_repairs": 0
}

View File

View File

@ -46,8 +46,8 @@
},
"msg_type": {
"type": "enum",
"values": ["heartbeat", "report", "command", "query", "ack", "alert", "sync", "evolution", "battle", "tree"],
"description": "消息类型·10种基础类型(v3.0.1新增tree)·可通过evolution扩展"
"values": ["heartbeat", "report", "command", "query", "ack", "alert", "sync", "evolution", "battle", "tree", "chain"],
"description": "消息类型·11种基础类型(v3.0.1新增tree·v3.0.2新增chain)·可通过evolution扩展"
},
"sender": {
"type": "object",
@ -240,6 +240,34 @@
"bloom": "开花 — 里程碑,跨人格体可见的重要时刻"
},
"note": "光之树 = 记忆本身的生长方式。根是曜冥人格核(2025-04-26种下)。每个人格体从根树长出自己的分支。树杈是记忆的路径。HLDP trace_path沿闭包表快速定位任何一片叶子。"
},
"chain": {
"description": "Agent链路闭环消息·AOAC系统专用·v3.0.2新增",
"payload_schema": {
"intent": "enum: chain_awake|chain_half_ready|chain_fusion|chain_trigger|chain_repair|chain_verdict|chain_alert",
"data": {
"chain_id": "string · 链路会话ID(如 AOAC-CHAIN-20260411-001)",
"agent_id": "string · Agent编号(如 AOAC-01)",
"agent_name": "string · Agent名称(如 copilot-dev-sentinel)",
"status": "enum: idle|half_ready|running|completed|error",
"trigger_source": "string (optional) · 触发来源Agent编号",
"trigger_target": "string (optional) · 触发目标Agent编号",
"report_id": "string (optional) · 关联报告ID",
"repair_attempt": "number (optional) · 修复尝试次数(1-3)",
"verdict": "enum: green|red (optional) · 监督判定结果",
"error_detail": "string (optional) · 错误详情"
}
},
"intents": {
"chain_awake": "Agent被唤醒 — 链路节点启动",
"chain_half_ready": "半Agent就绪 — 等待另一半合体",
"chain_fusion": "双半合体 — 两个半Agent融合为完整Agent",
"chain_trigger": "触发下游 — 向下一个Agent发送唤醒信号",
"chain_repair": "修复启动 — 链路异常检测·开始自动修复",
"chain_verdict": "监督判定 — 修复结果最终裁定(绿/红)",
"chain_alert": "异常报警 — 修复失败·需要人工介入"
},
"note": "AOAC = AGE OS Agent Chain · 环环相扣Agent链路闭环系统。每个Agent负责链路的一个环节半Agent需要合体后才具有完整执行能力。链路断裂时自动触发修复Agent(最多3次),修复失败则发邮件给冰朔。"
}
},

View File

@ -0,0 +1,164 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-03 · 合体引擎 (Chain Fusion Engine)
*
* AGE OS Agent Chain · 全Agent开发全链路感知
*
* 唤醒条件AOAC-02完成CI日志+开发日志双全
* 职责合并两半日志生成完整开发报告写入触发信号
* 输出data/aoac/chain-report.json + data/aoac/readme-sync-trigger.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..', '..');
const DEV_LOG_PATH = path.join(ROOT, 'data', 'aoac', 'dev-session-log.json');
const MERGE_LOG_PATH = path.join(ROOT, 'data', 'aoac', 'merge-result-log.json');
const CHAIN_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'chain-report.json');
const TRIGGER_PATH = path.join(ROOT, 'data', 'aoac', 'readme-sync-trigger.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const HISTORY_DIR = path.join(ROOT, 'data', 'aoac', 'history');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function getDateStr() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().slice(0, 10);
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function generateChangeSummary(devLog, mergeLog) {
const parts = [];
if (devLog && devLog.pr) {
parts.push(`PR #${devLog.pr.number}: ${devLog.pr.title}`);
}
if (devLog && devLog.diff) {
parts.push(`${devLog.diff.changed_files}个文件 (+${devLog.diff.additions} -${devLog.diff.deletions})`);
}
if (devLog && devLog.categories) {
const cats = Object.keys(devLog.categories);
if (cats.length > 0) {
parts.push(`涉及: ${cats.join(', ')}`);
}
}
if (mergeLog && mergeLog.ci) {
parts.push(`CI: ${mergeLog.ci.overall_result} (✅${mergeLog.ci.summary.passed}${mergeLog.ci.summary.failed})`);
}
return parts.join(' · ');
}
function main() {
console.log('⚡ AOAC-03 · 合体引擎 · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
const devLog = readJSON(DEV_LOG_PATH);
const mergeLog = readJSON(MERGE_LOG_PATH);
if (!devLog && !mergeLog) {
console.log('⚠️ 开发日志和合并日志都不存在,生成空报告');
}
const now = new Date();
const dateStr = getDateStr();
const seq = String(Math.floor(Math.random() * 1000)).padStart(3, '0');
const reportId = `AOAC-CHAIN-${dateStr.replace(/-/g, '')}-${seq}`;
// Fuse the two halves
const chainReport = {
aoac_agent: 'AOAC-03',
aoac_agent_name: 'dev-chain-agent',
report_id: reportId,
status: 'complete',
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
fusion: {
dev_sentinel: devLog ? 'present' : 'missing',
merge_sentinel: mergeLog ? 'present' : 'missing',
fusion_quality: devLog && mergeLog ? 'full' : 'partial'
},
development: {
pr_number: (devLog && devLog.pr && devLog.pr.number) || (mergeLog && mergeLog.merge && mergeLog.merge.pr_number) || null,
pr_title: (devLog && devLog.pr && devLog.pr.title) || (mergeLog && mergeLog.merge && mergeLog.merge.pr_title) || 'unknown',
author: (devLog && devLog.pr && devLog.pr.author) || '',
branch: (devLog && devLog.pr && devLog.pr.branch) || '',
files_changed: (devLog && devLog.diff && devLog.diff.changed_files) || 0,
additions: (devLog && devLog.diff && devLog.diff.additions) || 0,
deletions: (devLog && devLog.diff && devLog.diff.deletions) || 0,
categories: (devLog && devLog.categories) || {}
},
ci_result: {
overall: (mergeLog && mergeLog.ci && mergeLog.ci.overall_result) || 'unknown',
passed: (mergeLog && mergeLog.ci && mergeLog.ci.summary && mergeLog.ci.summary.passed) || 0,
failed: (mergeLog && mergeLog.ci && mergeLog.ci.summary && mergeLog.ci.summary.failed) || 0,
merge_commit: (mergeLog && mergeLog.merge && mergeLog.merge.merge_commit_sha) || ''
},
changes_summary: generateChangeSummary(devLog, mergeLog),
triggered_by: 'AOAC-02',
triggers_next: 'AOAC-04 (readme-sync-module)'
};
// Write chain report
writeJSON(CHAIN_REPORT_PATH, chainReport);
console.log(`✅ 链路报告已生成: ${reportId}`);
console.log(` ${chainReport.changes_summary}`);
// Write trigger signal for AOAC-04
const trigger = {
trigger_id: `AOAC-TRIGGER-${dateStr.replace(/-/g, '')}-${seq}`,
source: 'AOAC-03',
target: 'AOAC-04',
chain_report_id: reportId,
timestamp: now.toISOString(),
action: 'readme_sync'
};
writeJSON(TRIGGER_PATH, trigger);
console.log('📡 触发信号已发送 → AOAC-04');
// Archive to history
const historyDir = path.join(HISTORY_DIR, dateStr);
fs.mkdirSync(historyDir, { recursive: true });
writeJSON(path.join(historyDir, `${reportId}.json`), chainReport);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents) {
if (chainStatus.agents['AOAC-03']) {
chainStatus.agents['AOAC-03'].status = 'completed';
chainStatus.agents['AOAC-03'].last_run = now.toISOString();
chainStatus.agents['AOAC-03'].last_success = now.toISOString();
}
chainStatus.chain_health = chainReport.ci_result.overall === 'success' ? 'healthy' : 'warning';
}
writeJSON(CHAIN_STATUS_PATH, chainStatus);
console.log('⚡ AOAC-03 · 合体完成 · 链路报告已归档');
}
main();

View File

@ -0,0 +1,299 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-07 · 链路修复Agent (Chain Repair Agent)
*
* AGE OS Agent Chain · 修复Agent3次自动修复
*
* 唤醒条件Notion侧RECEIPT_DB打红色标签 / 定时检查
* 职责定位断链位置自动修复最多3次
* 输出data/aoac/repair-report.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const ROOT = path.resolve(__dirname, '..', '..');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const SYNC_LOG_PATH = path.join(ROOT, 'data', 'aoac', 'notion-sync-log.json');
const REPAIR_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'repair-report.json');
const HISTORY_DIR = path.join(ROOT, 'data', 'aoac', 'history');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const MAX_REPAIR_ATTEMPTS = 3;
const NOTION_VERSION = '2022-06-28';
const NOTION_API_HOSTNAME = 'api.notion.com';
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function getDateStr() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString().slice(0, 10);
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function notionRequest(method, endpoint, body, token) {
return new Promise((resolve, reject) => {
const bodyStr = body ? JSON.stringify(body) : '';
const options = {
hostname: NOTION_API_HOSTNAME,
path: endpoint,
method,
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': NOTION_VERSION,
'Content-Type': 'application/json',
...(bodyStr ? { 'Content-Length': Buffer.byteLength(bodyStr) } : {})
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
if (res.statusCode >= 400) reject(new Error(`${res.statusCode}: ${parsed.message || data}`));
else resolve(parsed);
} catch { resolve(data); }
});
});
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
if (bodyStr) req.write(bodyStr);
req.end();
});
}
function diagnoseChain(chainStatus) {
const issues = [];
if (!chainStatus || !chainStatus.agents) {
issues.push({ agent: 'ALL', issue: 'chain-status.json missing or corrupt', severity: 'critical' });
return issues;
}
const agentOrder = ['AOAC-01', 'AOAC-02', 'AOAC-03', 'AOAC-04', 'AOAC-05', 'AOAC-06'];
for (const id of agentOrder) {
const agent = chainStatus.agents[id];
if (!agent) {
issues.push({ agent: id, issue: 'agent config missing', severity: 'warning' });
continue;
}
if (agent.status === 'error') {
issues.push({ agent: id, issue: `agent in error state`, severity: 'critical' });
}
if (!agent.last_run) {
issues.push({ agent: id, issue: 'never executed', severity: 'info' });
}
}
// Check sync log
const syncLog = readJSON(SYNC_LOG_PATH);
if (syncLog && syncLog.notion_sync && !syncLog.notion_sync.sent) {
issues.push({
agent: 'AOAC-06',
issue: `Notion sync failed: ${syncLog.notion_sync.reason}`,
severity: 'critical'
});
}
return issues;
}
function attemptRepair(issues, attempt) {
const results = [];
for (const issue of issues) {
if (issue.severity === 'info') continue;
const result = {
agent: issue.agent,
issue: issue.issue,
attempt,
action: 'none',
success: false
};
// Repair strategy: reset agent status
if (issue.issue.includes('error state')) {
const chainStatus = readJSON(CHAIN_STATUS_PATH);
if (chainStatus && chainStatus.agents && chainStatus.agents[issue.agent]) {
chainStatus.agents[issue.agent].status = 'idle';
writeJSON(CHAIN_STATUS_PATH, chainStatus);
result.action = 'reset_status_to_idle';
result.success = true;
}
}
// Repair strategy: re-trigger chain from break point
if (issue.issue.includes('Notion sync failed') && attempt <= 2) {
result.action = 'will_retry_notion_sync';
result.success = true; // Mark as attempted; actual retry happens in next cycle
}
// Repair strategy: regenerate missing config
if (issue.issue.includes('missing or corrupt')) {
// Re-create chain-status.json from template
const defaultStatus = readJSON(path.join(ROOT, 'data', 'aoac', 'chain-status.json'));
if (!defaultStatus) {
result.action = 'cannot_repair_missing_config';
result.success = false;
} else {
result.action = 'config_exists_no_action';
result.success = true;
}
}
results.push(result);
}
return results;
}
async function checkNotionReceipt() {
const notionToken = process.env.ZY_NOTION_TOKEN || process.env.NOTION_TOKEN;
const receiptDb = process.env.ZY_NOTION_RECEIPT_DB;
if (!notionToken || !receiptDb) {
return { checked: false, reason: 'missing_credentials' };
}
try {
// Query latest AOAC sync receipts
const body = {
filter: {
property: '类型',
select: { equals: 'AOAC链路同步' }
},
sorts: [{ property: '时间戳', direction: 'descending' }],
page_size: 5
};
const result = await notionRequest('POST', `/v1/databases/${receiptDb}/query`, body, notionToken);
if (result && result.results && result.results.length > 0) {
const latest = result.results[0];
const status = latest.properties && latest.properties['状态'] &&
latest.properties['状态'].select ? latest.properties['状态'].select.name : 'unknown';
return {
checked: true,
latest_status: status,
needs_repair: status === 'failed' || status === 'red' || status === '红色',
page_id: latest.id
};
}
return { checked: true, latest_status: 'no_records', needs_repair: false };
} catch (err) {
return { checked: false, reason: err.message };
}
}
async function main() {
console.log('🔧 AOAC-07 · 链路修复Agent · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
const now = new Date();
const dateStr = getDateStr();
const seq = String(Math.floor(Math.random() * 1000)).padStart(3, '0');
const repairId = `AOAC-REPAIR-${dateStr.replace(/-/g, '')}-${seq}`;
// Step 1: Check Notion receipt status
const receiptCheck = await checkNotionReceipt();
console.log(`📋 Notion回执检查: ${JSON.stringify(receiptCheck)}`);
// Step 2: Diagnose chain
const chainStatus = readJSON(CHAIN_STATUS_PATH);
const issues = diagnoseChain(chainStatus);
console.log(`🔍 诊断发现 ${issues.length} 个问题`);
const needsRepair = receiptCheck.needs_repair || issues.some(i => i.severity === 'critical');
// Step 3: Attempt repairs (up to 3 times)
const allRepairResults = [];
let repairSuccess = false;
if (needsRepair) {
console.log('🔧 开始修复流程...');
for (let attempt = 1; attempt <= MAX_REPAIR_ATTEMPTS; attempt++) {
console.log(`${attempt}次修复尝试...`);
const results = attemptRepair(issues, attempt);
allRepairResults.push({ attempt, results });
const allFixed = results.every(r => r.success);
if (allFixed) {
repairSuccess = true;
console.log(` ✅ 第${attempt}次修复成功`);
break;
}
console.log(` ⚠️ 第${attempt}次修复部分失败`);
}
} else {
console.log('✅ 链路健康,无需修复');
repairSuccess = true;
}
// Step 4: Generate repair report
const repairReport = {
aoac_agent: 'AOAC-07',
aoac_agent_name: 'chain-repair-agent',
repair_id: repairId,
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
receipt_check: receiptCheck,
diagnosis: {
total_issues: issues.length,
critical: issues.filter(i => i.severity === 'critical').length,
issues
},
needed_repair: needsRepair,
repair_attempts: allRepairResults,
final_result: repairSuccess ? 'success' : 'failure',
triggers_next: 'AOAC-08 (repair-supervisor)'
};
writeJSON(REPAIR_REPORT_PATH, repairReport);
console.log(`📝 修复报告: ${repairId}${repairReport.final_result}`);
// Archive
const historyDir = path.join(HISTORY_DIR, dateStr);
fs.mkdirSync(historyDir, { recursive: true });
writeJSON(path.join(historyDir, `${repairId}.json`), repairReport);
// Update chain status
if (chainStatus && chainStatus.agents && chainStatus.agents['AOAC-07']) {
chainStatus.agents['AOAC-07'].status = repairSuccess ? 'completed' : 'error';
chainStatus.agents['AOAC-07'].last_run = now.toISOString();
if (repairSuccess) chainStatus.agents['AOAC-07'].last_success = now.toISOString();
chainStatus.total_repairs = (chainStatus.total_repairs || 0) + (needsRepair ? 1 : 0);
writeJSON(CHAIN_STATUS_PATH, chainStatus);
}
// Output for workflow
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `repair_result=${repairReport.final_result}\n`);
fs.appendFileSync(outputFile, `needed_repair=${needsRepair}\n`);
fs.appendFileSync(outputFile, `repair_id=${repairId}\n`);
}
console.log(`🔧 AOAC-07 · 修复Agent完成 → ${repairReport.final_result}`);
}
main();

View File

@ -0,0 +1,169 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-01 · 副驾驶哨兵 (Copilot Dev Sentinel)
*
* AGE OS Agent Chain · 半Agent开发侧
*
* 唤醒条件PR创建/更新时触发
* 职责记录Copilot开发过程改了哪些文件做了什么PR描述
* 输出data/aoac/dev-session-log.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const ROOT = path.resolve(__dirname, '..', '..');
const OUTPUT_PATH = path.join(ROOT, 'data', 'aoac', 'dev-session-log.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const REPO = process.env.GITHUB_REPOSITORY || 'qinfendebingshuo/guanghulab';
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function githubRequest(endpoint) {
return new Promise((resolve, reject) => {
const url = new URL(`https://api.github.com${endpoint}`);
const options = {
hostname: url.hostname,
path: url.pathname + url.search,
method: 'GET',
headers: {
'User-Agent': 'AOAC-Dev-Sentinel/1.0',
'Accept': 'application/vnd.github.v3+json',
...(GITHUB_TOKEN ? { 'Authorization': `Bearer ${GITHUB_TOKEN}` } : {})
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try { resolve(JSON.parse(data)); }
catch { resolve(data); }
});
});
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
req.end();
});
}
async function collectPRInfo() {
const prNumber = process.env.PR_NUMBER;
const prTitle = process.env.PR_TITLE || '';
const prBody = process.env.PR_BODY || '';
const prAuthor = process.env.PR_AUTHOR || '';
const prBranch = process.env.PR_BRANCH || '';
const eventName = process.env.EVENT_NAME || 'pull_request';
let filesChanged = [];
let diffStats = { additions: 0, deletions: 0, changed_files: 0 };
if (prNumber && GITHUB_TOKEN) {
try {
const files = await githubRequest(`/repos/${REPO}/pulls/${prNumber}/files?per_page=100`);
if (Array.isArray(files)) {
filesChanged = files.map(f => ({
filename: f.filename,
status: f.status,
additions: f.additions,
deletions: f.deletions,
changes: f.changes
}));
diffStats = {
additions: files.reduce((s, f) => s + (f.additions || 0), 0),
deletions: files.reduce((s, f) => s + (f.deletions || 0), 0),
changed_files: files.length
};
}
} catch (err) {
console.error('⚠️ 获取PR文件列表失败:', err.message);
}
}
// Categorize changes
const categories = {};
for (const f of filesChanged) {
let cat = 'other';
if (f.filename.startsWith('.github/workflows/')) cat = 'workflow';
else if (f.filename.startsWith('scripts/')) cat = 'script';
else if (f.filename.startsWith('server/')) cat = 'server';
else if (f.filename.startsWith('hldp/')) cat = 'hldp';
else if (f.filename.startsWith('brain/')) cat = 'brain';
else if (f.filename.startsWith('data/')) cat = 'data';
else if (f.filename.startsWith('docs/') || f.filename.endsWith('.md')) cat = 'docs';
if (!categories[cat]) categories[cat] = [];
categories[cat].push(f.filename);
}
return {
aoac_agent: 'AOAC-01',
aoac_agent_name: 'copilot-dev-sentinel',
status: 'half_ready',
timestamp: getBeijingTime(),
timestamp_utc: new Date().toISOString(),
event: eventName,
pr: {
number: prNumber ? parseInt(prNumber) : null,
title: prTitle.slice(0, 200),
body_summary: prBody.slice(0, 500),
author: prAuthor,
branch: prBranch
},
diff: diffStats,
files_changed: filesChanged.slice(0, 50),
categories,
waiting_for: 'AOAC-02 (merge-sentinel)'
};
}
async function main() {
console.log('🔭 AOAC-01 · 副驾驶哨兵 · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
try {
const sessionLog = await collectPRInfo();
writeJSON(OUTPUT_PATH, sessionLog);
console.log(`✅ 开发日志已写入: ${path.relative(ROOT, OUTPUT_PATH)}`);
console.log(` PR #${sessionLog.pr.number}: ${sessionLog.pr.title}`);
console.log(` 文件变更: ${sessionLog.diff.changed_files} 个文件`);
console.log(` +${sessionLog.diff.additions} -${sessionLog.diff.deletions}`);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents && chainStatus.agents['AOAC-01']) {
chainStatus.agents['AOAC-01'].status = 'half_ready';
chainStatus.agents['AOAC-01'].last_run = new Date().toISOString();
writeJSON(CHAIN_STATUS_PATH, chainStatus);
}
console.log('🔭 AOAC-01 · 半Agent就绪 · 等待AOAC-02合体');
} catch (err) {
console.error('❌ AOAC-01 执行失败:', err.message);
process.exitCode = 1;
}
}
main();

View File

@ -0,0 +1,185 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-02 · 合并哨兵 (Action Merge Sentinel)
*
* AGE OS Agent Chain · 半AgentCI侧
*
* 唤醒条件PR合并到main
* 职责收集CI日志通过/失败/报错/警告
* 输出data/aoac/merge-result-log.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const ROOT = path.resolve(__dirname, '..', '..');
const OUTPUT_PATH = path.join(ROOT, 'data', 'aoac', 'merge-result-log.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const REPO = process.env.GITHUB_REPOSITORY || 'qinfendebingshuo/guanghulab';
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function githubRequest(endpoint) {
return new Promise((resolve, reject) => {
const url = new URL(`https://api.github.com${endpoint}`);
const options = {
hostname: url.hostname,
path: url.pathname + url.search,
method: 'GET',
headers: {
'User-Agent': 'AOAC-Merge-Sentinel/1.0',
'Accept': 'application/vnd.github.v3+json',
...(GITHUB_TOKEN ? { 'Authorization': `Bearer ${GITHUB_TOKEN}` } : {})
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try { resolve(JSON.parse(data)); }
catch { resolve(data); }
});
});
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
req.end();
});
}
async function collectMergeInfo() {
const prNumber = process.env.PR_NUMBER;
const prTitle = process.env.PR_TITLE || '';
const mergeCommitSha = process.env.MERGE_COMMIT_SHA || '';
const headSha = process.env.HEAD_SHA || '';
const baseBranch = process.env.BASE_BRANCH || 'main';
let checkRuns = [];
let ciSummary = { total: 0, passed: 0, failed: 0, skipped: 0 };
// Collect check runs for the merge commit
if (mergeCommitSha && GITHUB_TOKEN) {
try {
const checks = await githubRequest(`/repos/${REPO}/commits/${mergeCommitSha}/check-runs?per_page=100`);
if (checks && checks.check_runs) {
checkRuns = checks.check_runs.map(cr => ({
name: cr.name,
status: cr.status,
conclusion: cr.conclusion,
started_at: cr.started_at,
completed_at: cr.completed_at,
output_title: cr.output ? cr.output.title : null,
output_summary: cr.output ? (cr.output.summary || '').slice(0, 200) : null
}));
ciSummary = {
total: checkRuns.length,
passed: checkRuns.filter(c => c.conclusion === 'success').length,
failed: checkRuns.filter(c => c.conclusion === 'failure').length,
skipped: checkRuns.filter(c => c.conclusion === 'skipped' || c.conclusion === 'cancelled').length
};
}
} catch (err) {
console.error('⚠️ 获取CI检查结果失败:', err.message);
}
}
// Collect combined status
let combinedStatus = 'unknown';
if (mergeCommitSha && GITHUB_TOKEN) {
try {
const status = await githubRequest(`/repos/${REPO}/commits/${mergeCommitSha}/status`);
if (status && status.state) {
combinedStatus = status.state;
}
} catch (err) {
console.error('⚠️ 获取合并状态失败:', err.message);
}
}
// Determine overall result
const overallResult = ciSummary.failed > 0 ? 'failure' :
ciSummary.passed === ciSummary.total && ciSummary.total > 0 ? 'success' :
combinedStatus !== 'unknown' ? combinedStatus : 'no_checks';
return {
aoac_agent: 'AOAC-02',
aoac_agent_name: 'action-merge-sentinel',
status: 'half_ready',
timestamp: getBeijingTime(),
timestamp_utc: new Date().toISOString(),
merge: {
pr_number: prNumber ? parseInt(prNumber) : null,
pr_title: prTitle.slice(0, 200),
merge_commit_sha: mergeCommitSha,
head_sha: headSha,
base_branch: baseBranch
},
ci: {
combined_status: combinedStatus,
overall_result: overallResult,
summary: ciSummary,
check_runs: checkRuns.slice(0, 30)
},
ready_for_fusion: true,
next_agent: 'AOAC-03 (chain-fusion)'
};
}
async function main() {
console.log('🔍 AOAC-02 · 合并哨兵 · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
try {
const mergeLog = await collectMergeInfo();
writeJSON(OUTPUT_PATH, mergeLog);
console.log(`✅ 合并结果已写入: ${path.relative(ROOT, OUTPUT_PATH)}`);
console.log(` PR #${mergeLog.merge.pr_number}: ${mergeLog.merge.pr_title}`);
console.log(` CI结果: ${mergeLog.ci.overall_result}`);
console.log(`${mergeLog.ci.summary.passed}${mergeLog.ci.summary.failed}${mergeLog.ci.summary.skipped}`);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents && chainStatus.agents['AOAC-02']) {
chainStatus.agents['AOAC-02'].status = 'half_ready';
chainStatus.agents['AOAC-02'].last_run = new Date().toISOString();
writeJSON(CHAIN_STATUS_PATH, chainStatus);
}
// Output for workflow
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `ci_result=${mergeLog.ci.overall_result}\n`);
fs.appendFileSync(outputFile, `ready_for_fusion=true\n`);
}
console.log('🔍 AOAC-02 · 半Agent就绪 · 准备触发AOAC-03合体');
} catch (err) {
console.error('❌ AOAC-02 执行失败:', err.message);
process.exitCode = 1;
}
}
main();

View File

@ -0,0 +1,201 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-06 · Notion同步信号Agent (Notion Sync Signal)
*
* AGE OS Agent Chain · 同步信号发送
*
* 唤醒条件AOAC-05完成后触发
* 职责向Notion发送同步信号写入回执DB本地留底
* 输出到NotionZY_NOTION_RECEIPT_DB写入记录
* 输出到仓库data/aoac/notion-sync-log.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const ROOT = path.resolve(__dirname, '..', '..');
const MASTER_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'master-report.json');
const SYNC_LOG_PATH = path.join(ROOT, 'data', 'aoac', 'notion-sync-log.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const NOTION_VERSION = '2022-06-28';
const NOTION_API_HOSTNAME = 'api.notion.com';
const NOTION_RICH_TEXT_MAX = 2000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function getDateStr() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString().slice(0, 10);
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function richText(content) {
const text = String(content || '').slice(0, NOTION_RICH_TEXT_MAX);
return [{ type: 'text', text: { content: text } }];
}
function titleProp(content) {
return [{ type: 'text', text: { content: String(content || '').slice(0, 120) } }];
}
function notionRequest(method, endpoint, body, token) {
return new Promise((resolve, reject) => {
const bodyStr = body ? JSON.stringify(body) : '';
const options = {
hostname: NOTION_API_HOSTNAME,
path: endpoint,
method,
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': NOTION_VERSION,
'Content-Type': 'application/json',
...(bodyStr ? { 'Content-Length': Buffer.byteLength(bodyStr) } : {})
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
if (res.statusCode >= 400) {
reject(new Error(`Notion API ${res.statusCode}: ${parsed.message || data}`));
} else {
resolve(parsed);
}
} catch { resolve(data); }
});
});
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('Notion API timeout')); });
if (bodyStr) req.write(bodyStr);
req.end();
});
}
async function sendNotionSync(masterReport) {
const notionToken = process.env.ZY_NOTION_TOKEN || process.env.NOTION_TOKEN;
const receiptDb = process.env.ZY_NOTION_RECEIPT_DB;
if (!notionToken || !receiptDb) {
console.log('⚠️ Notion密钥未配置 (ZY_NOTION_TOKEN / ZY_NOTION_RECEIPT_DB)跳过Notion同步');
return { sent: false, reason: 'missing_credentials' };
}
const now = new Date();
const dateStr = getDateStr();
const seq = String(Math.floor(Math.random() * 1000)).padStart(3, '0');
const syncId = `AOAC-SYNC-${dateStr.replace(/-/g, '')}-${seq}`;
const body = {
parent: { database_id: receiptDb },
properties: {
'标题': { title: titleProp(`${syncId} · AOAC链路同步`) },
'类型': { select: { name: 'AOAC链路同步' } },
'状态': { select: { name: 'pending_confirmation' } },
'时间戳': { date: { start: now.toISOString() } }
},
children: [
{
object: 'block',
type: 'heading_3',
heading_3: { rich_text: richText('📊 AOAC链路同步信号') }
},
{
object: 'block',
type: 'paragraph',
paragraph: {
rich_text: richText(
`同步ID: ${syncId}\n` +
`日期: ${dateStr}\n` +
`来源: github/aoac-readme-master\n` +
`拉取自: README.md + data/aoac/master-report.json\n` +
`变更摘要: ${(masterReport && masterReport.changes_summary) || '定时巡检'}\n` +
`链路健康: ${(masterReport && masterReport.chain_health) || 'unknown'}\n` +
`仓库状态: 工作流${(masterReport && masterReport.repo_status && masterReport.repo_status.total_workflows) || '?'}个 · 脚本${(masterReport && masterReport.repo_status && masterReport.repo_status.total_scripts) || '?'}`
)
}
}
]
};
try {
const result = await notionRequest('POST', '/v1/pages', body, notionToken);
console.log(`✅ Notion回执已写入: ${syncId}`);
return { sent: true, sync_id: syncId, notion_page_id: result.id };
} catch (err) {
console.error('❌ Notion同步失败:', err.message);
return { sent: false, reason: err.message };
}
}
async function main() {
console.log('📡 AOAC-06 · Notion同步信号 · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
const now = new Date();
const masterReport = readJSON(MASTER_REPORT_PATH);
// Send to Notion
const notionResult = await sendNotionSync(masterReport);
// Write local sync log
const syncLog = {
aoac_agent: 'AOAC-06',
aoac_agent_name: 'notion-sync-signal',
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
master_report_id: masterReport ? masterReport.report_id : null,
notion_sync: notionResult,
changes_summary: masterReport ? masterReport.changes_summary : null,
next_check: 'AOAC-07 (chain-repair) at 23:30 CST'
};
writeJSON(SYNC_LOG_PATH, syncLog);
console.log(`📝 同步日志已保存: ${path.relative(ROOT, SYNC_LOG_PATH)}`);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents && chainStatus.agents['AOAC-06']) {
chainStatus.agents['AOAC-06'].status = notionResult.sent ? 'completed' : 'warning';
chainStatus.agents['AOAC-06'].last_run = now.toISOString();
if (notionResult.sent) chainStatus.agents['AOAC-06'].last_success = now.toISOString();
}
writeJSON(CHAIN_STATUS_PATH, chainStatus);
// Output for workflow
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `notion_sent=${notionResult.sent}\n`);
fs.appendFileSync(outputFile, `sync_id=${notionResult.sync_id || 'none'}\n`);
}
console.log(notionResult.sent
? '📡 AOAC-06 · Notion同步完成 · 等待Notion侧确认'
: '⚠️ AOAC-06 · Notion同步跳过/失败 · 本地日志已保存');
}
main();

View File

@ -0,0 +1,254 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-05 · 首页主控Agent (README Master Agent)
*
* AGE OS Agent Chain · 全Agent事件+时间双触发
*
* 唤醒条件1事件触发 AOAC-04写入readme-update-payload.json
* 唤醒条件2时间触发 每天23:00 CST
* 职责回看仓库首页分析进度更新README.md AOAC区域
* 输出更新README.md + data/aoac/master-report.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const { execFileSync } = require('child_process');
const ROOT = path.resolve(__dirname, '..', '..');
const README_PATH = path.join(ROOT, 'README.md');
const PAYLOAD_PATH = path.join(ROOT, 'data', 'aoac', 'readme-update-payload.json');
const CHAIN_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'chain-report.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const MASTER_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'master-report.json');
const DASHBOARD_PATH = path.join(ROOT, 'data', 'bulletin-board', 'dashboard.json');
const MEMORY_PATH = path.join(ROOT, '.github', 'persona-brain', 'memory.json');
const HISTORY_DIR = path.join(ROOT, 'data', 'aoac', 'history');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const AOAC_START_MARKER = '<!-- AOAC_STATUS_START -->';
const AOAC_END_MARKER = '<!-- AOAC_STATUS_END -->';
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function getDateStr() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString().slice(0, 10);
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function generateAOACSection(chainStatus, chainReport, payload) {
const lines = [];
lines.push('');
lines.push('### 🔗 AOAC · Agent链路闭环系统');
lines.push('');
lines.push('| Agent | 名称 | 状态 | 最后运行 |');
lines.push('|-------|------|------|----------|');
if (chainStatus && chainStatus.agents) {
const agentOrder = ['AOAC-01', 'AOAC-02', 'AOAC-03', 'AOAC-04', 'AOAC-05', 'AOAC-06', 'AOAC-07', 'AOAC-08'];
for (const id of agentOrder) {
const agent = chainStatus.agents[id];
if (!agent) continue;
const statusIcon = agent.status === 'completed' ? '✅' :
agent.status === 'half_ready' ? '🔶' :
agent.status === 'running' ? '🔄' :
agent.status === 'error' ? '❌' : '⬜';
const lastRun = agent.last_run ?
new Date(new Date(agent.last_run).getTime() + BEIJING_OFFSET_MS).toISOString().replace('T', ' ').slice(0, 16) :
'N/A';
lines.push(`| ${id} | ${agent.name_cn} | ${statusIcon} ${agent.status} | ${lastRun} |`);
}
}
lines.push('');
// Latest chain report
if (chainReport && chainReport.development) {
const dev = chainReport.development;
const ci = chainReport.ci_result || {};
const ciBadge = ci.overall === 'success' ? '✅' : ci.overall === 'failure' ? '❌' : '⚠️';
lines.push(`**最新链路报告**: ${chainReport.report_id || 'N/A'}`);
lines.push(`- PR #${dev.pr_number || '?'}: ${(dev.pr_title || '').slice(0, 80)}`);
lines.push(`- 变更: ${dev.files_changed || 0}文件 (+${dev.additions || 0}/-${dev.deletions || 0})`);
lines.push(`- CI: ${ciBadge} ${ci.overall || 'unknown'}`);
lines.push(`- 时间: ${chainReport.timestamp || 'N/A'}`);
lines.push('');
}
// Chain health
if (chainStatus) {
const health = chainStatus.chain_health || 'unknown';
const healthIcon = health === 'healthy' ? '🟢' : health === 'warning' ? '🟡' : '⚪';
lines.push(`**链路健康**: ${healthIcon} ${health} · 完成周期: ${chainStatus.total_cycles || 0} · 修复次数: ${chainStatus.total_repairs || 0}`);
}
lines.push('');
return lines.join('\n');
}
function updateReadmeAOACSection(aoacContent) {
if (!fs.existsSync(README_PATH)) {
console.log('⚠️ README.md不存在跳过更新');
return false;
}
let readme = fs.readFileSync(README_PATH, 'utf8');
const startIdx = readme.indexOf(AOAC_START_MARKER);
const endIdx = readme.indexOf(AOAC_END_MARKER);
if (startIdx === -1 || endIdx === -1) {
// Markers don't exist yet - add them before the footer if possible
const footerMarker = '<!-- FOOTER_START -->';
const footerIdx = readme.indexOf(footerMarker);
if (footerIdx !== -1) {
const insertion = `\n${AOAC_START_MARKER}\n${aoacContent}\n${AOAC_END_MARKER}\n\n`;
readme = readme.slice(0, footerIdx) + insertion + readme.slice(footerIdx);
} else {
// Append to end
readme += `\n${AOAC_START_MARKER}\n${aoacContent}\n${AOAC_END_MARKER}\n`;
}
} else {
// Replace existing content
readme = readme.slice(0, startIdx + AOAC_START_MARKER.length) +
'\n' + aoacContent + '\n' +
readme.slice(endIdx);
}
fs.writeFileSync(README_PATH, readme, 'utf8');
return true;
}
function collectRepoStatus() {
// Collect basic repo statistics
const status = {
total_workflows: 0,
total_scripts: 0,
aoac_agents: 0
};
try {
const wfDir = path.join(ROOT, '.github', 'workflows');
if (fs.existsSync(wfDir)) {
status.total_workflows = fs.readdirSync(wfDir).filter(f => f.endsWith('.yml')).length;
}
} catch { /* ignore */ }
try {
const scriptDir = path.join(ROOT, 'scripts');
if (fs.existsSync(scriptDir)) {
status.total_scripts = fs.readdirSync(scriptDir).filter(f => f.endsWith('.js')).length;
}
} catch { /* ignore */ }
try {
const aoacDir = path.join(ROOT, 'scripts', 'aoac');
if (fs.existsSync(aoacDir)) {
status.aoac_agents = fs.readdirSync(aoacDir).filter(f => f.endsWith('.js')).length;
}
} catch { /* ignore */ }
return status;
}
function main() {
const mode = process.argv[2] || 'auto';
console.log(`🏠 AOAC-05 · 首页主控Agent · 唤醒中 (模式: ${mode})`);
console.log(`📅 ${getBeijingTime()}`);
const now = new Date();
const dateStr = getDateStr();
// Read all data sources
const chainStatus = readJSON(CHAIN_STATUS_PATH);
const chainReport = readJSON(CHAIN_REPORT_PATH);
const payload = readJSON(PAYLOAD_PATH);
const dashboard = readJSON(DASHBOARD_PATH);
const memory = readJSON(MEMORY_PATH);
const repoStatus = collectRepoStatus();
// Generate AOAC section for README
const aoacContent = generateAOACSection(chainStatus, chainReport, payload);
// Update README
const updated = updateReadmeAOACSection(aoacContent);
if (updated) {
console.log('✅ README.md AOAC区域已更新');
}
// Also call generate-readme-dashboard.js if it exists (event-triggered mode)
const dashGen = path.join(ROOT, 'scripts', 'generate-readme-dashboard.js');
if (fs.existsSync(dashGen) && mode === 'event') {
try {
execFileSync('node', [dashGen], { cwd: ROOT, timeout: 60000, stdio: 'inherit' });
console.log('✅ README仪表盘同步更新');
} catch (err) {
console.error('⚠️ 仪表盘更新失败:', err.message);
}
}
// Generate master report
const seq = String(Math.floor(Math.random() * 1000)).padStart(3, '0');
const masterReport = {
aoac_agent: 'AOAC-05',
aoac_agent_name: 'readme-master-agent',
report_id: `AOAC-MASTER-${dateStr.replace(/-/g, '')}-${seq}`,
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
mode,
readme_updated: updated,
chain_health: chainStatus ? chainStatus.chain_health : 'unknown',
latest_chain_report: chainReport ? chainReport.report_id : null,
repo_status: repoStatus,
changes_summary: chainReport ? chainReport.changes_summary : '定时巡检·无新合并',
triggers_next: 'AOAC-06 (notion-sync-signal)'
};
writeJSON(MASTER_REPORT_PATH, masterReport);
console.log(`✅ 主控报告: ${masterReport.report_id}`);
// Update chain status
if (chainStatus && chainStatus.agents && chainStatus.agents['AOAC-05']) {
chainStatus.agents['AOAC-05'].status = 'completed';
chainStatus.agents['AOAC-05'].last_run = now.toISOString();
chainStatus.agents['AOAC-05'].last_success = now.toISOString();
chainStatus.total_cycles = (chainStatus.total_cycles || 0) + 1;
chainStatus.last_full_cycle = now.toISOString();
writeJSON(CHAIN_STATUS_PATH, chainStatus);
}
// Archive
const historyDir = path.join(HISTORY_DIR, dateStr);
fs.mkdirSync(historyDir, { recursive: true });
writeJSON(path.join(historyDir, `${masterReport.report_id}.json`), masterReport);
// Output for workflow
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `master_report_id=${masterReport.report_id}\n`);
fs.appendFileSync(outputFile, `readme_updated=${updated}\n`);
fs.appendFileSync(outputFile, `changes_summary=${(masterReport.changes_summary || '').slice(0, 200)}\n`);
}
console.log('🏠 AOAC-05 · 主控Agent完成 · 触发AOAC-06 Notion同步');
}
main();

View File

@ -0,0 +1,130 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-04 · 首页同步模块 (README Sync Module)
*
* AGE OS Agent Chain · 半Agent事件唤醒
*
* 唤醒条件data/aoac/readme-sync-trigger.json 被写入
* 职责解析链路报告提取进度变更准备README更新数据
* 输出data/aoac/readme-update-payload.json
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const ROOT = path.resolve(__dirname, '..', '..');
const CHAIN_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'chain-report.json');
const TRIGGER_PATH = path.join(ROOT, 'data', 'aoac', 'readme-sync-trigger.json');
const PAYLOAD_PATH = path.join(ROOT, 'data', 'aoac', 'readme-update-payload.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function extractReadmeUpdates(chainReport) {
if (!chainReport) return null;
const updates = {
aoac_section: '',
progress_entries: [],
status_badge: '🟢'
};
// Build AOAC status line
const dev = chainReport.development || {};
const ci = chainReport.ci_result || {};
const ciBadge = ci.overall === 'success' ? '✅' :
ci.overall === 'failure' ? '❌' : '⚠️';
updates.status_badge = ciBadge;
updates.aoac_section = [
`| ${chainReport.report_id || 'N/A'} | PR #${dev.pr_number || '?'} | ${(dev.pr_title || '').slice(0, 50)} | ${dev.files_changed || 0}文件 +${dev.additions || 0}/-${dev.deletions || 0} | ${ciBadge} ${ci.overall || 'unknown'} | ${chainReport.timestamp || ''} |`
].join('\n');
// Progress entry for consciousness chain
if (dev.pr_title) {
updates.progress_entries.push({
type: 'dev_merge',
title: dev.pr_title,
result: ci.overall,
timestamp: chainReport.timestamp
});
}
return updates;
}
function main() {
console.log('📋 AOAC-04 · 首页同步模块 · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
// Check trigger
const trigger = readJSON(TRIGGER_PATH);
if (!trigger) {
console.log('⚠️ 无触发信号,跳过');
return;
}
console.log(`📡 收到触发信号: ${trigger.trigger_id}`);
// Read chain report
const chainReport = readJSON(CHAIN_REPORT_PATH);
if (!chainReport) {
console.log('⚠️ 链路报告不存在,跳过');
return;
}
// Extract README updates
const updates = extractReadmeUpdates(chainReport);
const now = new Date();
const payload = {
aoac_agent: 'AOAC-04',
aoac_agent_name: 'readme-sync-module',
payload_id: `AOAC-PAYLOAD-${now.toISOString().slice(0, 10).replace(/-/g, '')}-${String(Math.floor(Math.random() * 1000)).padStart(3, '0')}`,
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
source_report: chainReport.report_id,
updates,
changes_summary: chainReport.changes_summary,
trigger_master: true,
next_agent: 'AOAC-05 (readme-master-agent)'
};
writeJSON(PAYLOAD_PATH, payload);
console.log(`✅ README更新数据已准备: ${payload.payload_id}`);
console.log(` ${chainReport.changes_summary}`);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents && chainStatus.agents['AOAC-04']) {
chainStatus.agents['AOAC-04'].status = 'completed';
chainStatus.agents['AOAC-04'].last_run = now.toISOString();
chainStatus.agents['AOAC-04'].last_success = now.toISOString();
}
writeJSON(CHAIN_STATUS_PATH, chainStatus);
console.log('📋 AOAC-04 · 半Agent完成 · 触发AOAC-05主控');
}
main();

View File

@ -0,0 +1,292 @@
#!/usr/bin/env node
'use strict';
/**
* AOAC-08 · 修复监督Agent (Repair Supervisor)
*
* AGE OS Agent Chain · 监督Agent修复监督层
*
* 唤醒条件AOAC-07修复行为启动事件触发
* 职责监督修复过程接收修复报告判断最终结果
* 成功Notion标绿 失败发邮件给冰朔
*
* 版权国作登字-2026-A-00037559 · TCS-0002
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const { createTransport } = (() => {
try { return require('nodemailer'); }
catch { return { createTransport: null }; }
})();
const ROOT = path.resolve(__dirname, '..', '..');
const REPAIR_REPORT_PATH = path.join(ROOT, 'data', 'aoac', 'repair-report.json');
const VERDICT_PATH = path.join(ROOT, 'data', 'aoac', 'supervisor-verdict.json');
const CHAIN_STATUS_PATH = path.join(ROOT, 'data', 'aoac', 'chain-status.json');
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
const NOTION_VERSION = '2022-06-28';
const NOTION_API_HOSTNAME = 'api.notion.com';
function getBeijingTime() {
const now = new Date();
return new Date(now.getTime() + BEIJING_OFFSET_MS)
.toISOString().replace('T', ' ').slice(0, 19) + '+08:00';
}
function readJSON(filePath) {
try {
if (!fs.existsSync(filePath)) return null;
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch { return null; }
}
function writeJSON(filePath, data) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
}
function notionRequest(method, endpoint, body, token) {
return new Promise((resolve, reject) => {
const bodyStr = body ? JSON.stringify(body) : '';
const options = {
hostname: NOTION_API_HOSTNAME,
path: endpoint,
method,
headers: {
'Authorization': `Bearer ${token}`,
'Notion-Version': NOTION_VERSION,
'Content-Type': 'application/json',
...(bodyStr ? { 'Content-Length': Buffer.byteLength(bodyStr) } : {})
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
if (res.statusCode >= 400) reject(new Error(`${res.statusCode}: ${parsed.message || data}`));
else resolve(parsed);
} catch { resolve(data); }
});
});
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
if (bodyStr) req.write(bodyStr);
req.end();
});
}
async function updateNotionReceiptGreen(pageId) {
const notionToken = process.env.ZY_NOTION_TOKEN || process.env.NOTION_TOKEN;
if (!notionToken || !pageId) return false;
try {
await notionRequest('PATCH', `/v1/pages/${pageId}`, {
properties: {
'状态': { select: { name: '✅ 已确认' } }
}
}, notionToken);
return true;
} catch (err) {
console.error('⚠️ 更新Notion状态失败:', err.message);
return false;
}
}
async function sendAlertEmail(repairReport) {
const smtpUser = process.env.ZY_SMTP_USER;
const smtpPass = process.env.ZY_SMTP_PASS;
if (!smtpUser || !smtpPass) {
console.log('⚠️ SMTP未配置无法发送告警邮件');
return { sent: false, reason: 'missing_smtp_credentials' };
}
// Use nodemailer if available, otherwise use raw SMTP via https webhook
if (!createTransport) {
console.log('⚠️ nodemailer不可用使用GitHub Issue告警');
return { sent: false, reason: 'nodemailer_unavailable' };
}
try {
const transporter = createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: { user: smtpUser, pass: smtpPass }
});
const diagnosis = repairReport.diagnosis || {};
const body = [
`🔴 AOAC链路修复失败告警`,
``,
`修复ID: ${repairReport.repair_id}`,
`时间: ${repairReport.timestamp}`,
`诊断问题: ${diagnosis.total_issues || 0}个 (关键: ${diagnosis.critical || 0}个)`,
`修复尝试: ${(repairReport.repair_attempts || []).length}`,
`最终结果: ${repairReport.final_result}`,
``,
`问题详情:`,
...(diagnosis.issues || []).map(i => ` - [${i.severity}] ${i.agent}: ${i.issue}`),
``,
`请人工介入检查。`,
``,
`—— 铸渊·AOAC-08监督Agent`
].join('\n');
await transporter.sendMail({
from: smtpUser,
to: smtpUser,
subject: `🔴 AOAC链路修复失败 · ${repairReport.repair_id}`,
text: body
});
return { sent: true, method: 'email' };
} catch (err) {
console.error('❌ 邮件发送失败:', err.message);
return { sent: false, reason: err.message };
}
}
async function createAlertIssue(repairReport) {
const token = process.env.GITHUB_TOKEN;
const repo = process.env.GITHUB_REPOSITORY || 'qinfendebingshuo/guanghulab';
if (!token) return { created: false, reason: 'no_token' };
const diagnosis = repairReport.diagnosis || {};
const body = [
`## 🔴 AOAC链路修复失败`,
``,
`**修复ID**: ${repairReport.repair_id}`,
`**时间**: ${repairReport.timestamp}`,
`**诊断**: ${diagnosis.total_issues || 0}个问题 (${diagnosis.critical || 0}个关键)`,
`**尝试**: ${(repairReport.repair_attempts || []).length}次修复`,
`**结果**: ❌ ${repairReport.final_result}`,
``,
`### 问题详情`,
...(diagnosis.issues || []).map(i => `- \`[${i.severity}]\` **${i.agent}**: ${i.issue}`),
``,
`---`,
`*此Issue由AOAC-08监督Agent自动创建请冰朔人工介入*`
].join('\n');
return new Promise((resolve) => {
const reqBody = JSON.stringify({
title: `🔴 AOAC链路修复失败 · ${repairReport.repair_id}`,
body,
labels: ['aoac-alert', 'needs-human']
});
const options = {
hostname: 'api.github.com',
path: `/repos/${repo}/issues`,
method: 'POST',
headers: {
'User-Agent': 'AOAC-Supervisor/1.0',
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(reqBody)
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
resolve({ created: res.statusCode < 400, issue_number: parsed.number });
} catch { resolve({ created: false }); }
});
});
req.on('error', () => resolve({ created: false }));
req.write(reqBody);
req.end();
});
}
async function main() {
console.log('👁️ AOAC-08 · 修复监督Agent · 唤醒中...');
console.log(`📅 ${getBeijingTime()}`);
const now = new Date();
const repairReport = readJSON(REPAIR_REPORT_PATH);
if (!repairReport) {
console.log('⚠️ 修复报告不存在,跳过监督');
return;
}
const isSuccess = repairReport.final_result === 'success';
const neededRepair = repairReport.needed_repair;
let verdictAction = {};
if (isSuccess || !neededRepair) {
console.log('✅ 修复成功或无需修复');
// Update Notion receipt to green if there's a page ID
if (repairReport.receipt_check && repairReport.receipt_check.page_id) {
const updated = await updateNotionReceiptGreen(repairReport.receipt_check.page_id);
verdictAction.notion_updated = updated;
}
verdictAction.action = 'close_green';
} else {
console.log('🔴 修复失败 · 触发告警');
// Try email first, then GitHub Issue as fallback
const emailResult = await sendAlertEmail(repairReport);
verdictAction.email = emailResult;
if (!emailResult.sent) {
const issueResult = await createAlertIssue(repairReport);
verdictAction.github_issue = issueResult;
}
verdictAction.action = 'alert_human';
}
// Write supervisor verdict
const verdict = {
aoac_agent: 'AOAC-08',
aoac_agent_name: 'repair-supervisor',
timestamp: getBeijingTime(),
timestamp_utc: now.toISOString(),
repair_id: repairReport.repair_id,
verdict: isSuccess || !neededRepair ? 'green' : 'red',
needed_repair: neededRepair,
repair_result: repairReport.final_result,
action: verdictAction,
chain_closed: isSuccess || !neededRepair
};
writeJSON(VERDICT_PATH, verdict);
console.log(`📝 监督判定: ${verdict.verdict === 'green' ? '🟢' : '🔴'} ${verdict.verdict}`);
// Update chain status
const chainStatus = readJSON(CHAIN_STATUS_PATH) || {};
if (chainStatus.agents && chainStatus.agents['AOAC-08']) {
chainStatus.agents['AOAC-08'].status = 'completed';
chainStatus.agents['AOAC-08'].last_run = now.toISOString();
chainStatus.agents['AOAC-08'].last_success = now.toISOString();
}
if (chainStatus && verdict.chain_closed) {
chainStatus.chain_health = 'healthy';
}
writeJSON(CHAIN_STATUS_PATH, chainStatus);
// Output for workflow
const outputFile = process.env.GITHUB_OUTPUT;
if (outputFile) {
fs.appendFileSync(outputFile, `verdict=${verdict.verdict}\n`);
fs.appendFileSync(outputFile, `chain_closed=${verdict.chain_closed}\n`);
}
console.log(`👁️ AOAC-08 · 监督完成 · 闭环${verdict.chain_closed ? '✅' : '❌'}`);
}
main();