| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- import fs from "node:fs/promises";
- import path from "node:path";
- const allowedStatuses = new Set(["working", "idle", "warning", "offline"]);
- const allowedAvatarKinds = new Set([
- "female-analyst",
- "male-ops",
- "female-researcher",
- "male-dispatcher",
- "female-observer",
- "male-maintainer"
- ]);
- function usage() {
- console.error("Usage: node scripts/sync-openclaw-agent-feed.mjs <source-json> [target-json]");
- process.exit(1);
- }
- function assertString(value, field, agentId) {
- if (typeof value !== "string" || value.trim() === "") {
- throw new Error(`Invalid ${field} for agent ${agentId}`);
- }
- }
- function assertNumber(value, field, agentId) {
- if (typeof value !== "number" || Number.isNaN(value)) {
- throw new Error(`Invalid ${field} for agent ${agentId}`);
- }
- }
- function normalizeAgent(agent) {
- const agentId = typeof agent.id === "string" ? agent.id : "unknown";
- assertString(agent.id, "id", agentId);
- assertString(agent.name, "name", agentId);
- assertString(agent.role, "role", agentId);
- assertString(agent.host, "host", agentId);
- assertString(agent.owner, "owner", agentId);
- assertString(agent.currentTask, "currentTask", agentId);
- assertString(agent.taskId, "taskId", agentId);
- assertString(agent.taskStage, "taskStage", agentId);
- assertString(agent.uptime, "uptime", agentId);
- assertString(agent.lastHeartbeat, "lastHeartbeat", agentId);
- assertString(agent.updatedAt, "updatedAt", agentId);
- assertString(agent.lastOutput, "lastOutput", agentId);
- assertNumber(agent.queueDepth, "queueDepth", agentId);
- assertNumber(agent.todayCompleted, "todayCompleted", agentId);
- if (!allowedStatuses.has(agent.status)) {
- throw new Error(`Invalid status for agent ${agentId}`);
- }
- if (agent.avatarKind && !allowedAvatarKinds.has(agent.avatarKind)) {
- throw new Error(`Invalid avatarKind for agent ${agentId}`);
- }
- return {
- id: agent.id,
- name: agent.name,
- role: agent.role,
- avatarKind: agent.avatarKind ?? "male-dispatcher",
- status: agent.status,
- statusLabel: typeof agent.statusLabel === "string" && agent.statusLabel ? agent.statusLabel : undefined,
- host: agent.host,
- owner: agent.owner,
- currentTask: agent.currentTask,
- taskId: agent.taskId,
- taskStage: agent.taskStage,
- queueDepth: agent.queueDepth,
- todayCompleted: agent.todayCompleted,
- uptime: agent.uptime,
- lastHeartbeat: agent.lastHeartbeat,
- updatedAt: agent.updatedAt,
- lastOutput: agent.lastOutput,
- lastError: typeof agent.lastError === "string" ? agent.lastError : undefined,
- tags: Array.isArray(agent.tags) ? agent.tags.filter((tag) => typeof tag === "string") : []
- };
- }
- async function main() {
- const [, , sourceArg, targetArg] = process.argv;
- if (!sourceArg) {
- usage();
- }
- const sourcePath = path.resolve(sourceArg);
- const targetPath = path.resolve(targetArg ?? path.join(process.cwd(), "storage", "agents", "openclaw-agents.json"));
- const raw = await fs.readFile(sourcePath, "utf8");
- const parsed = JSON.parse(raw);
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.agents)) {
- throw new Error("Feed JSON must contain an agents array");
- }
- const normalized = {
- fetchedAt: typeof parsed.fetchedAt === "string" ? parsed.fetchedAt : new Date().toISOString(),
- agents: parsed.agents.map(normalizeAgent)
- };
- await fs.mkdir(path.dirname(targetPath), { recursive: true });
- const tempPath = `${targetPath}.tmp`;
- await fs.writeFile(tempPath, JSON.stringify(normalized, null, 2), "utf8");
- await fs.rename(tempPath, targetPath);
- console.log(`OpenClaw agent feed synced to ${targetPath}`);
- console.log(`Agents: ${normalized.agents.length}`);
- }
- main().catch((error) => {
- console.error(error instanceof Error ? error.message : String(error));
- process.exit(1);
- });
|