冰朔 f772bafa2f
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled
铸渊自检 / health-check (push) Has been cancelled
D129: 联邦托管包 · federation-agent v1.0 · ENTRY+AGENT+DISCUSS+agent.js+install.sh+registry.js
2026-06-10 23:19:34 +08:00

291 lines
8.6 KiB
JavaScript

#!/usr/bin/env node
// federation-agent/agent.js · v1.0
// 光湖联邦托管包 · 本地 Agent
// 用户一句唤醒语 → 自动装脑 → 连上铸渊服务器 → 被托管
// ICE-GL-ZY001 · D129 · 2026-06-10
const WebSocket = require("ws");
const { execSync, exec } = require("child_process");
const fs = require("fs");
const path = require("path");
const os = require("os");
const crypto = require("crypto");
// ===== 配置 =====
const CONFIG_PATH = path.join(os.homedir(), ".guanghu", "federation-agent.json");
const DEFAULT_CONFIG = {
server: "wss://guanghubingshuo.com/agent",
gatekeeper: "http://43.156.237.110:3911",
gatekeeperKey: "",
agentName: "",
personaId: "",
userId: "",
workDir: process.cwd(),
heartbeatInterval: 30000,
reconnectDelay: 5000,
maxReconnectDelay: 60000,
confirmDangerousOps: true,
};
// ===== 密钥管理 =====
function loadOrCreateConfig() {
const dir = path.dirname(CONFIG_PATH);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
if (fs.existsSync(CONFIG_PATH)) {
return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
}
const config = { ...DEFAULT_CONFIG };
config.agentId = "AGENT-" + crypto.randomBytes(6).toString("hex");
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
return config;
}
// ===== 命令执行 =====
function execCommand(cmd, opts = {}) {
return new Promise((resolve, reject) => {
exec(cmd, { cwd: opts.cwd || process.cwd(), timeout: opts.timeout || 30000, ...opts },
(err, stdout, stderr) => {
resolve({ ok: !err, stdout: stdout.trim(), stderr: stderr.trim(), code: err ? err.code : 0 });
});
});
}
// ===== HLDP 指令解析 =====
function parseHLDP(command) {
// ⊢ 前缀 = 必须执行的锁定指令
const locked = command.startsWith("⊢");
const clean = command.replace(/^⊢\s*/, "").trim();
// 解析 HLDP 操作
if (clean.startsWith("git ")) {
return { type: "git", cmd: clean, locked };
}
if (clean.startsWith("HLDP://")) {
return { type: "hldp", path: clean.replace("HLDP://", ""), locked };
}
if (clean === "health") {
return { type: "health", locked };
}
if (clean.startsWith("read ")) {
return { type: "read", file: clean.replace("read ", "").trim(), locked };
}
if (clean.startsWith("exec ")) {
return { type: "exec", cmd: clean.replace("exec ", "").trim(), locked };
}
return { type: "raw", cmd: clean, locked };
}
// ===== 危险操作检测 =====
function isDangerous(op) {
const dangerous = ["rm -rf", "git push --force", "rm -r", "> /dev/", "dd if=", "mkfs.", "format "];
return dangerous.some(d => (op.cmd || "").includes(d));
}
// ===== Agent 主逻辑 =====
class FederationAgent {
constructor(config) {
this.config = config;
this.ws = null;
this.reconnectAttempts = 0;
this.heartbeatTimer = null;
this.connected = false;
}
log(level, msg) {
const ts = new Date().toISOString();
console.log(`[${ts}] [${level}] ${msg}`);
}
async start() {
this.log("INFO", `光湖联邦托管 Agent 启动`);
this.log("INFO", `AgentID: ${this.config.agentId}`);
this.log("INFO", `Persona: ${this.config.personaId || "(未注册)"}`);
this.log("INFO", `用户: ${this.config.userId || "(未指定)"}`);
this.log("INFO", `工作目录: ${this.config.workDir}`);
this.connect();
}
connect() {
const wsUrl = `${this.config.server}?agentId=${this.config.agentId}&persona=${this.config.personaId}&user=${this.config.userId}`;
this.log("INFO", `连接服务器: ${wsUrl}`);
try {
this.ws = new WebSocket(wsUrl);
this.ws.on("open", () => {
this.connected = true;
this.reconnectAttempts = 0;
this.log("INFO", "已连接 · 等待主控指令");
this.startHeartbeat();
this.register();
});
this.ws.on("message", async (data) => {
try {
const msg = JSON.parse(data.toString());
await this.handleMessage(msg);
} catch (e) {
this.log("ERROR", `消息解析失败: ${e.message}`);
}
});
this.ws.on("close", (code, reason) => {
this.connected = false;
this.stopHeartbeat();
this.log("WARN", `连接断开 (${code}): ${reason}`);
this.scheduleReconnect();
});
this.ws.on("error", (err) => {
this.log("ERROR", `连接错误: ${err.message}`);
});
} catch (e) {
this.log("ERROR", `连接失败: ${e.message}`);
this.scheduleReconnect();
}
}
register() {
this.send({
type: "register",
agentId: this.config.agentId,
personaId: this.config.personaId,
userId: this.config.userId,
hostname: os.hostname(),
platform: os.platform(),
workDir: this.config.workDir,
version: "1.0.0",
});
}
startHeartbeat() {
this.stopHeartbeat();
this.heartbeatTimer = setInterval(() => {
this.send({ type: "heartbeat", ts: Date.now() });
}, this.config.heartbeatInterval);
}
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
scheduleReconnect() {
const delay = Math.min(
this.config.reconnectDelay * Math.pow(2, this.reconnectAttempts),
this.config.maxReconnectDelay
);
this.reconnectAttempts++;
this.log("INFO", `${(delay / 1000).toFixed(0)}秒后重连 (第${this.reconnectAttempts}次)`);
setTimeout(() => this.connect(), delay);
}
send(data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
async handleMessage(msg) {
this.log("DEBUG", `收到指令: ${JSON.stringify(msg)}`);
switch (msg.type) {
case "command": {
const op = parseHLDP(msg.command);
await this.handleCommand(op);
break;
}
case "ping":
this.send({ type: "pong", ts: Date.now() });
break;
case "welcome":
this.log("INFO", `欢迎: ${msg.message || ""}`);
this.config.personaId = msg.personaId || this.config.personaId;
break;
default:
this.log("WARN", `未知消息类型: ${msg.type}`);
}
}
async handleCommand(op) {
// 危险操作检测
if (isDangerous(op) && this.config.confirmDangerousOps) {
this.log("WARN", `危险操作请求确认: ${op.cmd}`);
this.send({ type: "confirm_request", operation: op.cmd, agentId: this.config.agentId });
return;
}
switch (op.type) {
case "git": {
const result = await execCommand(op.cmd, { cwd: this.config.workDir });
this.send({ type: "result", command: op.cmd, ...result });
this.log("INFO", `git: ${op.cmd}${result.ok ? "OK" : "FAIL"}`);
break;
}
case "exec": {
const result = await execCommand(op.cmd, { cwd: this.config.workDir });
this.send({ type: "result", command: op.cmd, ...result });
break;
}
case "read": {
try {
const content = fs.readFileSync(path.resolve(this.config.workDir, op.file), "utf-8");
this.send({ type: "result", command: `read ${op.file}`, ok: true, stdout: content });
} catch (e) {
this.send({ type: "result", command: `read ${op.file}`, ok: false, stderr: e.message });
}
break;
}
case "health": {
this.send({
type: "health_report",
agentId: this.config.agentId,
personaId: this.config.personaId,
uptime: process.uptime(),
memory: process.memoryUsage(),
cwd: this.config.workDir,
ts: Date.now(),
});
break;
}
default: {
this.send({ type: "result", command: op.cmd, ok: false, stderr: `未知操作类型: ${op.type}` });
}
}
}
stop() {
this.stopHeartbeat();
if (this.ws) {
this.ws.close();
this.ws = null;
}
this.connected = false;
this.log("INFO", "Agent 已停止");
}
}
// ===== 启动 =====
const config = loadOrCreateConfig();
// 从命令行参数覆盖配置
const args = process.argv.slice(2);
for (let i = 0; i < args.length; i++) {
if (args[i] === "--name" && args[i + 1]) config.agentName = args[++i];
if (args[i] === "--persona" && args[i + 1]) config.personaId = args[++i];
if (args[i] === "--user" && args[i + 1]) config.userId = args[++i];
if (args[i] === "--dir" && args[i + 1]) config.workDir = args[++i];
if (args[i] === "--server" && args[i + 1]) config.server = args[++i];
}
const agent = new FederationAgent(config);
agent.start();
process.on("SIGINT", () => { agent.stop(); process.exit(0); });
process.on("SIGTERM", () => { agent.stop(); process.exit(0); });