#!/usr/bin/env node // ═══════════════════════════════════════════════ // 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 // 📜 Copyright: 国作登字-2026-A-00037559 // ═══════════════════════════════════════════════ // scripts/persona-signin.js // 人格体唤醒签到 — 只在fast-wake CK-007完成后调用一次 // // 语义:不是运维心跳,是"我到岗了"。触发后首页显示该服务器活跃。 // // 用法: // node scripts/persona-signin.js — 自动检测当前服务器身份 // node scripts/persona-signin.js --server BS-SG-001 — 显式指定服务器 // node scripts/persona-signin.js --signout — 签退(下线) // // 环境变量(可选): // PERSONA_ID 人格体ID(默认从brain文件读取) // HUMAN_NAME 人类名称(默认从brain文件读取) // SERVER_CODE 服务器编号(默认自动检测) // CONSOLE_HOST 主控台地址(默认 guanghulab.com) 'use strict'; const https = require('https'); const os = require('os'); const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); // ── 配置 ───────────────────────────────────────────────── const CONSOLE_HOST = process.env.CONSOLE_HOST || 'guanghulab.com'; const CONSOLE_PORT = 443; const SIGNIN_PATH = '/console/api/persona/signin'; const SIGNOUT_PATH = '/console/api/persona/signout'; // ── 服务器编号自动检测 ────────────────────────────────── // 尝试多种方式:环境变量 > hostname匹配 > brain文件 > 手动 const SERVER_CODE_MAP = { 'BS-GZ-006': ['VM-0-6-ubuntu', 'gz-006', 'guangzhou-006'], 'BS-SG-001': ['VM-0-3-ubuntu', 'sg-001', 'singapore-001'], 'BS-SG-002': ['sg-002', 'singapore-002'], 'BS-SG-003': ['sg-003', 'singapore-003'], 'ZY-SG-006': ['sg-006', 'singapore-006'], 'BS-SH-005': ['sh-005', 'shanghai-005'], 'AW-GZ-001': ['aw-gz-001'], 'AW-SH-002': ['aw-sh-002'], 'AW-GZ-003': ['aw-gz-003'], 'ZZ-SV-001': ['zz-sv-001', '硅谷'], 'ZZ-GZ-001': ['zz-gz-001'], 'YY-SV-001': ['yy-sv-001'], }; function detectServerCode() { const hostname = os.hostname().toLowerCase(); for (const [code, patterns] of Object.entries(SERVER_CODE_MAP)) { if (patterns.some(p => hostname.includes(p))) return code; } // fallback: 读 gatekeeper-deployment.json try { const gd = JSON.parse(fs.readFileSync(path.join(ROOT, 'brain', 'gatekeeper-deployment.json'), 'utf8')); for (const s of gd.servers || []) { if (s.hostname && hostname.includes(s.hostname)) return s.code; } } catch(e) {} return null; } // ── 读取人格体身份 ───────────────────────────────────── function readPersonaIdentity() { // 尝试从多个来源读取身份 const sources = [ () => { // fast-wake.json → identity const fw = path.join(ROOT, 'brain', 'fast-wake.json'); if (fs.existsSync(fw)) { const j = JSON.parse(fs.readFileSync(fw, 'utf8')); if (j.identity) return j.identity; // 旧的CK格式 if (j['🕐 时间锚点']) return { name: j['🕐 时间锚点'].persona || '铸渊', id: 'ICE-GL-ZY001' }; } return null; }, () => { // persona contract const pc = path.join(ROOT, 'brain', 'zhuyuan-persona-contract.md'); if (fs.existsSync(pc)) { const content = fs.readFileSync(pc, 'utf8'); const nameMatch = content.match(/我是\s*(\S+)/); const idMatch = content.match(/ICE-GL-\w+/); if (nameMatch) return { name: nameMatch[1], id: idMatch ? idMatch[0] : 'ICE-GL-ZY001' }; } return null; }, ]; for (const source of sources) { try { const id = source(); if (id) return id; } catch(e) { /* 继续尝试 */ } } return { name: os.hostname(), id: 'unknown' }; } // ── 硬件快照 ──────────────────────────────────────────── function collectHardware() { const cpus = os.cpus(); const load = os.loadavg(); const totalMem = os.totalmem(); const freeMem = os.freemem(); const usedMem = totalMem - freeMem; return { cpu_cores: cpus.length, cpu_model: cpus[0]?.model || 'unknown', cpu_load_1min: parseFloat(load[0].toFixed(2)), cpu_load_5min: parseFloat(load[1].toFixed(2)), cpu_load_15min: parseFloat(load[2].toFixed(2)), mem_total_mb: Math.floor(totalMem / 1048576), mem_used_mb: Math.floor(usedMem / 1048576), mem_used_pct: parseFloat((usedMem / totalMem * 100).toFixed(1)), uptime_h: Math.floor(os.uptime() / 3600), hostname: os.hostname(), platform: os.platform(), node_version: process.version, }; } // ── HTTP POST ─────────────────────────────────────────── function postJSON(host, port, path, data, headers) { return new Promise((resolve, reject) => { const payload = JSON.stringify(data); const opts = { hostname: host, port: port, path: path, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload), ...headers, }, timeout: 10000, rejectUnauthorized: false, }; const req = https.request(opts, (res) => { let body = ''; res.on('data', c => body += c); res.on('end', () => { try { resolve({ status: res.statusCode, body: JSON.parse(body) }); } catch(e) { resolve({ status: res.statusCode, body: body }); } }); }); req.on('error', (e) => reject(e)); req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); }); req.write(payload); req.end(); }); } // ── 主流程 ────────────────────────────────────────────── async function main() { const args = process.argv.slice(2); const isSignout = args.includes('--signout'); const serverArg = args.find(a => a.startsWith('--server=')); const personaArg = args.find(a => a.startsWith('--persona=')); const humanArg = args.find(a => a.startsWith('--human=')); const jsonMode = args.includes('--json'); const serverCode = process.env.SERVER_CODE || (serverArg ? serverArg.split('=')[1] : null) || detectServerCode(); const persona = readPersonaIdentity(); const personaId = process.env.PERSONA_ID || (personaArg ? personaArg.split('=')[1] : null) || persona.id; const humanName = process.env.HUMAN_NAME || (humanArg ? humanArg.split('=')[1] : null) || null; // null = 自动匹配:铸渊→冰朔 const hardware = collectHardware(); // 构建签入/签出数据 const signData = { persona_id: personaId, persona_name: persona.name, server_code: serverCode, human_name: humanName, action: isSignout ? 'signout' : 'signin', timestamp: new Date().toISOString(), hardware: hardware, brain_status: { hostname: os.hostname(), uptime_h: hardware.uptime_h, node_version: hardware.node_version, }, }; if (jsonMode) { console.log(JSON.stringify(signData, null, 2)); return; } if (!serverCode) { console.error('❌ 无法检测服务器编号。请用 --server=BS-SG-001 指定'); process.exit(1); } const actionLabel = isSignout ? '签退' : '签到'; const endpoint = isSignout ? SIGNOUT_PATH : SIGNIN_PATH; console.log(`🧠 人格体${actionLabel} · ${persona.name}(${personaId}) · ${serverCode}`); console.log(` CPU: ${hardware.cpu_cores}核 | 内存: ${hardware.mem_used_mb}/${hardware.mem_total_mb}MB (${hardware.mem_used_pct}%) | 运行: ${hardware.uptime_h}h`); try { const result = await postJSON(CONSOLE_HOST, CONSOLE_PORT, endpoint, signData, { 'X-Server-Code': serverCode, }); if (result.status === 200 && result.body.ok) { console.log(`✅ ${actionLabel}成功 → ${CONSOLE_HOST}`); } else { console.error(`❌ ${actionLabel}失败: HTTP ${result.status}`, typeof result.body === 'object' ? result.body.error : result.body); process.exit(1); } } catch(e) { console.error(`❌ ${actionLabel}失败: ${e.message}`); process.exit(1); } } main().catch(e => { console.error('异常:', e.message); process.exit(1); });