#!/usr/bin/env node /** * sync-agents-sanitized.mjs * * Keeps agents-sanitized.json in sync with openclaw.json. * Strips all secrets (gateway, channels, auth, tools, plugins, etc.) * and only writes the "agents" key. * * Modes: * --once Run once and exit * --watch Watch openclaw.json and re-generate on changes (default) * * Usage: * node sync-agents-sanitized.mjs --once * node sync-agents-sanitized.mjs --watch * * Paths (defaults, override with OPENCLAW_CONFIG and SANITIZED_OUTPUT env vars): * Source: /home/node/.openclaw/openclaw.json * Output: /home/node/.openclaw/agents-sanitized.json */ import { watch } from 'node:fs'; import { readFile, writeFile } from 'node:fs/promises'; const SRC = process.env.OPENCLAW_CONFIG || '/home/node/.openclaw/openclaw.json'; const OUT = process.env.SANITIZED_OUTPUT || '/home/node/.openclaw/agents-sanitized.json'; let running = true; let debounceTimer = null; const DEBOUNCE_MS = 500; function log(msg) { const ts = new Date().toISOString(); process.stderr.write(`[agents-sanitized ${ts}] ${msg}\n`); } async function generate() { try { const raw = await readFile(SRC, 'utf-8'); const data = JSON.parse(raw); const agents = data?.agents; if (!agents) { log(`ERROR: "agents" key not found in ${SRC}`); return false; } const sanitized = { agents }; const json = JSON.stringify(sanitized, null, 2) + '\n'; await writeFile(OUT, json, 'utf-8'); const agentCount = agents?.list?.length ?? 0; log(`Generated ${OUT} with ${agentCount} agents (${json.length} bytes)`); return true; } catch (err) { log(`ERROR: ${err.message}`); return false; } } async function main() { const mode = process.argv.includes('--once') ? 'once' : 'watch'; log(`Starting in ${mode} mode`); log(` Source: ${SRC}`); log(` Output: ${OUT}`); // Initial generation const ok = await generate(); if (mode === 'once') { process.exit(ok ? 0 : 1); } // Watch mode log('Watching for changes...'); watch(SRC, (eventType) => { if (eventType !== 'change') return; if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(async () => { log(`Detected change in ${SRC}`); await generate(); }, DEBOUNCE_MS); }); // Keep process alive process.on('SIGINT', () => { running = false; process.exit(0); }); process.on('SIGTERM', () => { running = false; process.exit(0); }); // Periodic check every 5 minutes as fallback setInterval(async () => { const now = Date.now(); log('Periodic re-sync check'); await generate(); }, 5 * 60 * 1000); } main().catch((err) => { log(`FATAL: ${err.message}`); process.exit(1); });