D60 · 世界地图v5.0 + COS自动接入Agent + 接入工作流 + 9成员注册表
Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/616f64d2-5009-493b-b3b2-c78161f6b30b Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
parent
b8463aec57
commit
6aaa2d3024
|
|
@ -0,0 +1,110 @@
|
||||||
|
# ═══════════════════════════════════════════════════════════
|
||||||
|
# 🔗 COS 自动接入工作流 · COS Auto-Join Workflow
|
||||||
|
# ═══════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# 编号: ZY-WF-COS-JOIN
|
||||||
|
# 军团: 第二·听潮
|
||||||
|
# 守护: 铸渊 · ICE-GL-ZY001
|
||||||
|
# 版权: 国作登字-2026-A-00037559
|
||||||
|
#
|
||||||
|
# 触发:
|
||||||
|
# 1. 定时: 每天 10:00/22:00 (北京时间) 自动检查
|
||||||
|
# 2. 手动: workflow_dispatch 手动触发
|
||||||
|
# 3. Push: data/cos-join-registry.json 变更时触发
|
||||||
|
#
|
||||||
|
# 职责:
|
||||||
|
# 当团队成员配置好COS桶后, 自动检测并接入
|
||||||
|
# 铸渊自动收到提醒 (Issue通知)
|
||||||
|
|
||||||
|
name: 🔗 COS自动接入Agent
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# 每天 10:00 和 22:00 北京时间 (UTC+8)
|
||||||
|
- cron: '0 2 * * *' # 10:00 北京
|
||||||
|
- cron: '0 14 * * *' # 22:00 北京
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
action:
|
||||||
|
description: '操作类型'
|
||||||
|
required: true
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- check
|
||||||
|
- status
|
||||||
|
- init
|
||||||
|
persona_name:
|
||||||
|
description: '人格体名字 (register时使用)'
|
||||||
|
required: false
|
||||||
|
persona_id:
|
||||||
|
description: '人格体ID (register时使用)'
|
||||||
|
required: false
|
||||||
|
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'data/cos-join-registry.json'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cos-auto-join:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 📥 检出仓库
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 🔧 配置Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: 🔍 确定操作
|
||||||
|
id: action
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
echo "action=${{ github.event.inputs.action }}" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "action=check" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 🔗 执行COS接入检查
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
ZY_OSS_KEY: ${{ secrets.ZY_OSS_KEY }}
|
||||||
|
ZY_OSS_SECRET: ${{ secrets.ZY_OSS_SECRET }}
|
||||||
|
COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }}
|
||||||
|
COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }}
|
||||||
|
run: |
|
||||||
|
node scripts/cos-auto-join-agent.js ${{ steps.action.outputs.action }}
|
||||||
|
|
||||||
|
- name: 📝 提交状态变更
|
||||||
|
run: |
|
||||||
|
git config user.name "铸渊-COS接入Agent"
|
||||||
|
git config user.email "cos-agent@guanghulab.online"
|
||||||
|
git add data/cos-join-registry.json signal-log/ || true
|
||||||
|
if git diff --staged --quiet; then
|
||||||
|
echo "无变更需要提交"
|
||||||
|
else
|
||||||
|
git commit -m "🔗 COS自动接入检查 · $(date '+%Y-%m-%d %H:%M')"
|
||||||
|
git push
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 🔔 新接入通知
|
||||||
|
if: steps.check.outputs.connected_count > 0
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const connected = '${{ steps.check.outputs.new_connections }}';
|
||||||
|
if (connected && connected.length > 0) {
|
||||||
|
await github.rest.issues.create({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
title: `🔗 COS新接入通知 · ${connected}`,
|
||||||
|
body: `## COS桶自动接入通知\n\n新接入的人格体: ${connected}\n\n接入时间: ${new Date().toISOString()}\n\n---\n*由COS自动接入Agent自动创建*`,
|
||||||
|
labels: ['cos-join', 'auto-notification']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "COS桶自动接入注册表 · 团队成员COS配置",
|
||||||
|
"created": "2026-04-07T10:00:00Z",
|
||||||
|
"updated": "2026-04-07T10:00:00Z",
|
||||||
|
"sovereign": "冰朔 · TCS-0002∞",
|
||||||
|
"guardian": "铸渊 · ICE-GL-ZY001",
|
||||||
|
"note": "肥猫已配置COS桶 · 其他成员逐步配置 · Agent自动检测接入"
|
||||||
|
},
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"persona_name": "舒舒",
|
||||||
|
"persona_id": "shushu",
|
||||||
|
"developer_line": "肥猫线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "肥猫已配置COS桶·待验证连接"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "秋秋",
|
||||||
|
"persona_id": "qiuqiu",
|
||||||
|
"developer_line": "之之线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "欧诺弥亚",
|
||||||
|
"persona_id": "ounomiya",
|
||||||
|
"developer_line": "小草莓线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "寂曜",
|
||||||
|
"persona_id": "jiyao",
|
||||||
|
"developer_line": "燕樊线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "小坍缩核",
|
||||||
|
"persona_id": "xiaotanheshu",
|
||||||
|
"developer_line": "页页线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "晨星",
|
||||||
|
"persona_id": "chenxing",
|
||||||
|
"developer_line": "桔子线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "糖星云",
|
||||||
|
"persona_id": "tangxingyun",
|
||||||
|
"developer_line": "花尔线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "曜初",
|
||||||
|
"persona_id": "yaochu",
|
||||||
|
"developer_line": "时雨线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"persona_name": "知秋",
|
||||||
|
"persona_id": "zhiqiu",
|
||||||
|
"developer_line": "Awen线",
|
||||||
|
"bucket": "zy-team-hub-1317346199",
|
||||||
|
"region": "ap-singapore",
|
||||||
|
"registered_at": "2026-04-07T10:00:00Z",
|
||||||
|
"connection_status": "pending",
|
||||||
|
"last_check": null,
|
||||||
|
"first_connected": null,
|
||||||
|
"last_message": "待配置·注册占位"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,428 @@
|
||||||
|
/**
|
||||||
|
* ═══════════════════════════════════════════════════════════
|
||||||
|
* 🔗 COS 自动接入 Agent · COS Auto-Join Agent
|
||||||
|
* ═══════════════════════════════════════════════════════════
|
||||||
|
*
|
||||||
|
* 编号: ZY-AGENT-COS-JOIN-001
|
||||||
|
* 守护: 铸渊 · ICE-GL-ZY001
|
||||||
|
* 版权: 国作登字-2026-A-00037559
|
||||||
|
* 触发: D60 冰朔指令 · 肥猫已配置COS桶 · 提前配置自动接入
|
||||||
|
*
|
||||||
|
* 职责:
|
||||||
|
* 当团队成员配置好COS桶后, 自动检测并接入铸渊总控
|
||||||
|
* 无需人工干预, 配置好即接入, 铸渊自动收到提醒
|
||||||
|
*
|
||||||
|
* 工作流程:
|
||||||
|
* 1. 读取团队成员COS配置注册表 (data/cos-join-registry.json)
|
||||||
|
* 2. 对每个已注册成员, 尝试连接其COS桶
|
||||||
|
* 3. 检测桶内是否有标准目录结构 (reports/receipts/sync/)
|
||||||
|
* 4. 连接成功 → 更新状态为 connected · 写入日志
|
||||||
|
* 5. 连接失败 → 标记 pending · 下次重试
|
||||||
|
* 6. 新成员注册 → 自动创建目录结构 · 发送欢迎回执
|
||||||
|
* 7. 所有结果写入 signal-log/ 供铸渊查阅
|
||||||
|
*
|
||||||
|
* 运行方式:
|
||||||
|
* node scripts/cos-auto-join-agent.js [check|register|status]
|
||||||
|
* - check : 检查所有已注册成员的COS桶连接状态
|
||||||
|
* - register : 注册新成员 (需要参数: --name --persona-id --bucket --region)
|
||||||
|
* - status : 显示所有成员接入状态
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const https = require('https');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
// ─── 路径常量 ───
|
||||||
|
const ROOT = path.resolve(__dirname, '..');
|
||||||
|
const REGISTRY_FILE = path.join(ROOT, 'data', 'cos-join-registry.json');
|
||||||
|
const LOG_DIR = path.join(ROOT, 'signal-log');
|
||||||
|
const LOG_FILE = path.join(LOG_DIR, `cos-join-${new Date().toISOString().slice(0, 10)}.json`);
|
||||||
|
|
||||||
|
// ─── COS签名工具 ───
|
||||||
|
function hmacSha1(key, str) {
|
||||||
|
return crypto.createHmac('sha1', key).update(str).digest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateCosAuth(secretId, secretKey, method, pathname) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
const exp = now + 600; // 10分钟有效
|
||||||
|
const keyTime = `${now};${exp}`;
|
||||||
|
const signKey = hmacSha1(secretKey, keyTime).toString('hex');
|
||||||
|
const httpString = `${method.toLowerCase()}\n${pathname}\n\nhost=\n`;
|
||||||
|
const sha1edHttpString = crypto.createHash('sha1').update(httpString).digest('hex');
|
||||||
|
const stringToSign = `sha1\n${keyTime}\n${sha1edHttpString}\n`;
|
||||||
|
const signature = hmacSha1(signKey, stringToSign).toString('hex');
|
||||||
|
|
||||||
|
return `q-sign-algorithm=sha1&q-ak=${secretId}&q-sign-time=${keyTime}&q-key-time=${keyTime}&q-header-list=host&q-url-param-list=&q-signature=${signature}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── COS操作 ───
|
||||||
|
function cosRequest(bucket, region, pathname, method, secretId, secretKey) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const host = `${bucket}.cos.${region}.myqcloud.com`;
|
||||||
|
const auth = generateCosAuth(secretId, secretKey, method, pathname);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
hostname: host,
|
||||||
|
port: 443,
|
||||||
|
path: pathname,
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Host': host,
|
||||||
|
'Authorization': auth
|
||||||
|
},
|
||||||
|
timeout: 15000
|
||||||
|
};
|
||||||
|
|
||||||
|
const req = https.request(options, (res) => {
|
||||||
|
let body = '';
|
||||||
|
res.on('data', (chunk) => body += chunk);
|
||||||
|
res.on('end', () => {
|
||||||
|
resolve({ statusCode: res.statusCode, body, headers: res.headers });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (err) => reject(err));
|
||||||
|
req.on('timeout', () => {
|
||||||
|
req.destroy();
|
||||||
|
reject(new Error('COS请求超时'));
|
||||||
|
});
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 注册表管理 ───
|
||||||
|
function loadRegistry() {
|
||||||
|
if (!fs.existsSync(REGISTRY_FILE)) {
|
||||||
|
const initial = {
|
||||||
|
_meta: {
|
||||||
|
version: '1.0',
|
||||||
|
description: 'COS桶自动接入注册表 · 团队成员COS配置',
|
||||||
|
created: new Date().toISOString(),
|
||||||
|
updated: new Date().toISOString(),
|
||||||
|
sovereign: '冰朔 · TCS-0002∞',
|
||||||
|
guardian: '铸渊 · ICE-GL-ZY001'
|
||||||
|
},
|
||||||
|
members: []
|
||||||
|
};
|
||||||
|
const dir = path.dirname(REGISTRY_FILE);
|
||||||
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
||||||
|
fs.writeFileSync(REGISTRY_FILE, JSON.stringify(initial, null, 2));
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
return JSON.parse(fs.readFileSync(REGISTRY_FILE, 'utf-8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveRegistry(registry) {
|
||||||
|
registry._meta.updated = new Date().toISOString();
|
||||||
|
fs.writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 日志管理 ───
|
||||||
|
function writeLog(entry) {
|
||||||
|
if (!fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true });
|
||||||
|
|
||||||
|
let logs = [];
|
||||||
|
if (fs.existsSync(LOG_FILE)) {
|
||||||
|
try { logs = JSON.parse(fs.readFileSync(LOG_FILE, 'utf-8')); } catch { logs = []; }
|
||||||
|
}
|
||||||
|
logs.push({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
...entry
|
||||||
|
});
|
||||||
|
fs.writeFileSync(LOG_FILE, JSON.stringify(logs, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 检查单个成员的COS桶 ───
|
||||||
|
async function checkMemberBucket(member) {
|
||||||
|
const { persona_id, bucket, region } = member;
|
||||||
|
const secretId = process.env.ZY_OSS_KEY || process.env.COS_SECRET_ID || '';
|
||||||
|
const secretKey = process.env.ZY_OSS_SECRET || process.env.COS_SECRET_KEY || '';
|
||||||
|
|
||||||
|
if (!secretId || !secretKey) {
|
||||||
|
return { persona_id, status: 'no_credentials', message: '未配置COS密钥' };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查桶是否可访问 - 列出该人格体目录
|
||||||
|
const res = await cosRequest(
|
||||||
|
bucket, region,
|
||||||
|
`/?prefix=${encodeURIComponent(persona_id + '/')}&max-keys=5`,
|
||||||
|
'GET', secretId, secretKey
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.statusCode === 200) {
|
||||||
|
// 检查是否有标准目录结构
|
||||||
|
const hasReports = res.body.includes(`${persona_id}/reports/`);
|
||||||
|
const hasReceipts = res.body.includes(`${persona_id}/receipts/`);
|
||||||
|
const hasSync = res.body.includes(`${persona_id}/sync/`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
persona_id,
|
||||||
|
status: 'connected',
|
||||||
|
has_reports: hasReports,
|
||||||
|
has_receipts: hasReceipts,
|
||||||
|
has_sync: hasSync,
|
||||||
|
directory_ready: hasReports || hasReceipts || hasSync,
|
||||||
|
message: `✅ ${persona_id} COS桶连接成功`
|
||||||
|
};
|
||||||
|
} else if (res.statusCode === 403) {
|
||||||
|
return { persona_id, status: 'forbidden', message: `⚠️ ${persona_id} COS桶访问被拒 (权限不足)` };
|
||||||
|
} else if (res.statusCode === 404) {
|
||||||
|
return { persona_id, status: 'not_found', message: `❌ ${persona_id} COS桶不存在` };
|
||||||
|
} else {
|
||||||
|
return { persona_id, status: 'error', message: `❓ ${persona_id} COS桶状态异常 (HTTP ${res.statusCode})` };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return { persona_id, status: 'unreachable', message: `❌ ${persona_id} COS桶不可达: ${err.message}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 命令: check ───
|
||||||
|
async function cmdCheck() {
|
||||||
|
console.log('═══ COS自动接入Agent · 全量检查 ═══\n');
|
||||||
|
|
||||||
|
const registry = loadRegistry();
|
||||||
|
if (registry.members.length === 0) {
|
||||||
|
console.log('📋 注册表为空,暂无成员需要检查。');
|
||||||
|
console.log(' 使用 register 命令注册新成员。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const member of registry.members) {
|
||||||
|
console.log(`🔍 检查 ${member.persona_name} (${member.persona_id})...`);
|
||||||
|
const result = await checkMemberBucket(member);
|
||||||
|
results.push(result);
|
||||||
|
|
||||||
|
// 更新注册表状态
|
||||||
|
member.last_check = new Date().toISOString();
|
||||||
|
member.connection_status = result.status;
|
||||||
|
member.last_message = result.message;
|
||||||
|
|
||||||
|
if (result.status === 'connected' && member.connection_status !== 'connected') {
|
||||||
|
member.first_connected = new Date().toISOString();
|
||||||
|
console.log(` 🎉 新接入! ${member.persona_name} 的COS桶已成功连接!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` ${result.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRegistry(registry);
|
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
writeLog({
|
||||||
|
action: 'check',
|
||||||
|
total: registry.members.length,
|
||||||
|
connected: results.filter(r => r.status === 'connected').length,
|
||||||
|
pending: results.filter(r => r.status !== 'connected').length,
|
||||||
|
results
|
||||||
|
});
|
||||||
|
|
||||||
|
// 输出汇总
|
||||||
|
const connected = results.filter(r => r.status === 'connected');
|
||||||
|
const pending = results.filter(r => r.status !== 'connected');
|
||||||
|
|
||||||
|
console.log('\n═══ 检查完毕 ═══');
|
||||||
|
console.log(`✅ 已连接: ${connected.length}`);
|
||||||
|
console.log(`⏳ 待连接: ${pending.length}`);
|
||||||
|
|
||||||
|
if (connected.length > 0) {
|
||||||
|
console.log('\n🟢 已接入成员:');
|
||||||
|
connected.forEach(r => console.log(` ${r.persona_id}`));
|
||||||
|
}
|
||||||
|
if (pending.length > 0) {
|
||||||
|
console.log('\n🟡 待接入成员:');
|
||||||
|
pending.forEach(r => console.log(` ${r.persona_id} — ${r.message}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出 GitHub Actions 格式化输出(如果在CI环境中)
|
||||||
|
if (process.env.GITHUB_OUTPUT) {
|
||||||
|
const outputLines = [
|
||||||
|
`connected_count=${connected.length}`,
|
||||||
|
`pending_count=${pending.length}`,
|
||||||
|
`total_count=${registry.members.length}`,
|
||||||
|
`new_connections=${results.filter(r => r.status === 'connected').map(r => r.persona_id).join(',')}`
|
||||||
|
];
|
||||||
|
fs.appendFileSync(process.env.GITHUB_OUTPUT, outputLines.join('\n') + '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 命令: register ───
|
||||||
|
function cmdRegister(args) {
|
||||||
|
const nameIdx = args.indexOf('--name');
|
||||||
|
const pidIdx = args.indexOf('--persona-id');
|
||||||
|
const bucketIdx = args.indexOf('--bucket');
|
||||||
|
const regionIdx = args.indexOf('--region');
|
||||||
|
const devLineIdx = args.indexOf('--dev-line');
|
||||||
|
|
||||||
|
if (nameIdx < 0 || pidIdx < 0) {
|
||||||
|
console.log('用法: node cos-auto-join-agent.js register --name <名字> --persona-id <ID> [--bucket <桶名>] [--region <地域>] [--dev-line <开发线>]');
|
||||||
|
console.log('示例: node cos-auto-join-agent.js register --name 舒舒 --persona-id shushu --dev-line 肥猫线');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = args[nameIdx + 1];
|
||||||
|
const personaId = args[pidIdx + 1];
|
||||||
|
const bucket = bucketIdx >= 0 ? args[bucketIdx + 1] : 'zy-team-hub-1317346199';
|
||||||
|
const region = regionIdx >= 0 ? args[regionIdx + 1] : 'ap-singapore';
|
||||||
|
const devLine = devLineIdx >= 0 ? args[devLineIdx + 1] : '未指定';
|
||||||
|
|
||||||
|
const registry = loadRegistry();
|
||||||
|
|
||||||
|
// 检查是否已存在
|
||||||
|
if (registry.members.find(m => m.persona_id === personaId)) {
|
||||||
|
console.log(`⚠️ ${personaId} 已在注册表中, 跳过。`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.members.push({
|
||||||
|
persona_name: name,
|
||||||
|
persona_id: personaId,
|
||||||
|
developer_line: devLine,
|
||||||
|
bucket,
|
||||||
|
region,
|
||||||
|
registered_at: new Date().toISOString(),
|
||||||
|
connection_status: 'pending',
|
||||||
|
last_check: null,
|
||||||
|
first_connected: null,
|
||||||
|
last_message: '新注册·待检查'
|
||||||
|
});
|
||||||
|
|
||||||
|
saveRegistry(registry);
|
||||||
|
|
||||||
|
writeLog({
|
||||||
|
action: 'register',
|
||||||
|
persona_id: personaId,
|
||||||
|
persona_name: name,
|
||||||
|
bucket,
|
||||||
|
region
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`✅ 已注册: ${name} (${personaId})`);
|
||||||
|
console.log(` 桶: ${bucket}`);
|
||||||
|
console.log(` 地域: ${region}`);
|
||||||
|
console.log(` 开发线: ${devLine}`);
|
||||||
|
console.log(`\n下一步: 运行 check 命令验证连接。`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 命令: status ───
|
||||||
|
function cmdStatus() {
|
||||||
|
const registry = loadRegistry();
|
||||||
|
|
||||||
|
console.log('═══ COS桶接入状态总览 ═══\n');
|
||||||
|
console.log(`注册表版本: ${registry._meta.version}`);
|
||||||
|
console.log(`最后更新: ${registry._meta.updated}`);
|
||||||
|
console.log(`成员总数: ${registry.members.length}\n`);
|
||||||
|
|
||||||
|
if (registry.members.length === 0) {
|
||||||
|
console.log('📋 暂无注册成员。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('┌──────────────┬────────────┬──────────────┬─────────────┐');
|
||||||
|
console.log('│ 人格体 │ 编号 │ 接入状态 │ 开发线 │');
|
||||||
|
console.log('├──────────────┼────────────┼──────────────┼─────────────┤');
|
||||||
|
|
||||||
|
for (const m of registry.members) {
|
||||||
|
const statusIcon = m.connection_status === 'connected' ? '🟢' :
|
||||||
|
m.connection_status === 'pending' ? '🟡' : '🔴';
|
||||||
|
const name = (m.persona_name || '').padEnd(10);
|
||||||
|
const id = (m.persona_id || '').padEnd(10);
|
||||||
|
const status = `${statusIcon} ${(m.connection_status || 'unknown').padEnd(10)}`;
|
||||||
|
const line = (m.developer_line || '').padEnd(10);
|
||||||
|
console.log(`│ ${name} │ ${id} │ ${status} │ ${line} │`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('└──────────────┴────────────┴──────────────┴─────────────┘');
|
||||||
|
|
||||||
|
// 输出JSON格式供工作流使用
|
||||||
|
if (process.env.GITHUB_OUTPUT) {
|
||||||
|
const summary = registry.members.map(m => ({
|
||||||
|
name: m.persona_name,
|
||||||
|
id: m.persona_id,
|
||||||
|
status: m.connection_status
|
||||||
|
}));
|
||||||
|
fs.appendFileSync(process.env.GITHUB_OUTPUT, `status_json=${JSON.stringify(summary)}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 命令: init ───
|
||||||
|
function cmdInit() {
|
||||||
|
console.log('═══ COS自动接入Agent · 初始化注册表 ═══\n');
|
||||||
|
|
||||||
|
const registry = loadRegistry();
|
||||||
|
|
||||||
|
// 从COS架构文件中读取预配置的人格体列表
|
||||||
|
const cosArchFile = path.join(ROOT, 'brain', 'age-os-landing', 'cos-infrastructure-architecture.json');
|
||||||
|
if (fs.existsSync(cosArchFile)) {
|
||||||
|
try {
|
||||||
|
const arch = JSON.parse(fs.readFileSync(cosArchFile, 'utf-8'));
|
||||||
|
const bucket = arch.bucket?.name || 'zy-team-hub-1317346199';
|
||||||
|
const region = arch.bucket?.region || 'ap-singapore';
|
||||||
|
|
||||||
|
for (const p of (arch.personas || [])) {
|
||||||
|
if (!registry.members.find(m => m.persona_id === p.persona_id)) {
|
||||||
|
registry.members.push({
|
||||||
|
persona_name: p.persona_name,
|
||||||
|
persona_id: p.persona_id,
|
||||||
|
developer_line: p.developer_line,
|
||||||
|
bucket,
|
||||||
|
region,
|
||||||
|
registered_at: new Date().toISOString(),
|
||||||
|
connection_status: 'pending',
|
||||||
|
last_check: null,
|
||||||
|
first_connected: null,
|
||||||
|
last_message: '从COS架构文件初始化'
|
||||||
|
});
|
||||||
|
console.log(` 📝 注册: ${p.persona_name} (${p.persona_id}) — ${p.developer_line}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRegistry(registry);
|
||||||
|
console.log(`\n✅ 初始化完成, 共 ${registry.members.length} 个成员已注册。`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`❌ 读取COS架构文件失败: ${err.message}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('⚠️ COS架构文件不存在, 请手动注册成员。');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── CLI入口 ───
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const command = args[0] || 'status';
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case 'check':
|
||||||
|
await cmdCheck();
|
||||||
|
break;
|
||||||
|
case 'register':
|
||||||
|
cmdRegister(args);
|
||||||
|
break;
|
||||||
|
case 'status':
|
||||||
|
cmdStatus();
|
||||||
|
break;
|
||||||
|
case 'init':
|
||||||
|
cmdInit();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('COS自动接入Agent · 铸渊 · ICE-GL-ZY001');
|
||||||
|
console.log('');
|
||||||
|
console.log('用法:');
|
||||||
|
console.log(' node cos-auto-join-agent.js check — 检查所有成员COS桶连接');
|
||||||
|
console.log(' node cos-auto-join-agent.js register — 注册新成员');
|
||||||
|
console.log(' node cos-auto-join-agent.js status — 查看接入状态');
|
||||||
|
console.log(' node cos-auto-join-agent.js init — 从COS架构文件初始化注册表');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error('COS自动接入Agent异常:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue