#!/usr/bin/env node /** * Install / uninstall / update OpenClaw Perf Cache plugin. * * Usage: * node scripts/install.mjs --install # build + copy + register in openclaw.json * node scripts/install.mjs --uninstall # remove plugin + unregister * node scripts/install.mjs --update # rebuild + copy (no config touch) */ import fs from 'node:fs'; import path from 'node:path'; import { execSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const projRoot = path.resolve(__dirname, '..'); const pluginSrcDir = path.join(projRoot, 'plugin'); const PLUGIN_ID = 'openclaw-perf-cache'; const ocDir = path.join(process.env.HOME || '/root', '.openclaw'); const pluginsDir = path.join(ocDir, 'plugins'); const installDir = path.join(pluginsDir, PLUGIN_ID); const configPath = path.join(ocDir, 'openclaw.json'); const action = process.argv[2]; if (!action || !['--install', '--uninstall', '--update'].includes(action)) { console.log('Usage: node scripts/install.mjs --install | --uninstall | --update'); process.exit(1); } function build() { console.log('Building plugin TypeScript...'); execSync('npx tsc -p tsconfig.json', { cwd: pluginSrcDir, stdio: 'inherit' }); } function copyPluginFiles() { if (fs.existsSync(installDir)) fs.rmSync(installDir, { recursive: true }); fs.mkdirSync(installDir, { recursive: true }); // Copy compiled output + manifest + package.json. Skip the .ts source so // jiti uses the .js (no transpile overhead at load time) and skip tsconfig. for (const f of ['index.js', 'openclaw.plugin.json', 'package.json']) { const src = path.join(pluginSrcDir, f); const dst = path.join(installDir, f); if (!fs.existsSync(src)) { console.error(`missing ${src}; run build first`); process.exit(1); } fs.copyFileSync(src, dst); } console.log(`Copied to ${installDir}`); } function readConfig() { return JSON.parse(fs.readFileSync(configPath, 'utf8')); } function writeConfig(cfg) { fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2) + '\n', 'utf8'); } function registerInConfig() { const cfg = readConfig(); const plugins = (cfg.plugins ??= {}); const allow = (plugins.allow ??= []); const loadPaths = ((plugins.load ??= {}).paths ??= []); const entries = (plugins.entries ??= {}); if (!allow.includes(PLUGIN_ID)) allow.push(PLUGIN_ID); if (!loadPaths.includes(installDir)) loadPaths.push(installDir); const entry = (entries[PLUGIN_ID] ??= {}); if (entry.enabled === undefined) entry.enabled = true; writeConfig(cfg); console.log(`Registered ${PLUGIN_ID} in ${configPath}`); } function unregisterFromConfig() { const cfg = readConfig(); const plugins = cfg.plugins ?? {}; if (Array.isArray(plugins.allow)) { plugins.allow = plugins.allow.filter((id) => id !== PLUGIN_ID); } const loadPaths = plugins.load?.paths; if (Array.isArray(loadPaths)) { plugins.load.paths = loadPaths.filter((p) => p !== installDir); } if (plugins.entries && plugins.entries[PLUGIN_ID]) { delete plugins.entries[PLUGIN_ID]; } writeConfig(cfg); console.log(`Unregistered ${PLUGIN_ID} from ${configPath}`); } if (action === '--install') { build(); copyPluginFiles(); registerInConfig(); console.log('Done. Restart gateway to load: systemctl --user restart openclaw-gateway'); } else if (action === '--update') { build(); copyPluginFiles(); console.log('Updated. Restart gateway to reload: systemctl --user restart openclaw-gateway'); } else if (action === '--uninstall') { if (fs.existsSync(installDir)) { fs.rmSync(installDir, { recursive: true }); console.log(`Removed ${installDir}`); } unregisterFromConfig(); console.log('Done. Restart gateway to drop: systemctl --user restart openclaw-gateway'); }