#!/usr/bin/env node /** * Yonexus Plugin Installer v0.2.0 * * Usage: * node install.mjs --install * node install.mjs --install --openclaw-profile-path /path/to/.openclaw * node install.mjs --uninstall * node install.mjs --uninstall --openclaw-profile-path /path/to/.openclaw */ import { execSync } from 'child_process'; import { existsSync, mkdirSync, copyFileSync, readdirSync, rmSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir } from 'os'; const __filename = fileURLToPath(import.meta.url); const __dirname = resolve(dirname(__filename)); const PLUGIN_NAME = 'yonexus'; const SRC_DIST_DIR = join(__dirname, 'dist', PLUGIN_NAME); // ── Parse arguments ───────────────────────────────────────────────────── const args = process.argv.slice(2); const isInstall = args.includes('--install'); const isUninstall = args.includes('--uninstall'); const profileIdx = args.indexOf('--openclaw-profile-path'); let openclawProfilePath = null; if (profileIdx !== -1 && args[profileIdx + 1]) { openclawProfilePath = resolve(args[profileIdx + 1]); } function resolveOpenclawPath() { if (openclawProfilePath) return openclawProfilePath; if (process.env.OPENCLAW_PATH) return resolve(process.env.OPENCLAW_PATH); return join(homedir(), '.openclaw'); } // ── Colors ────────────────────────────────────────────────────────────── const c = { reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m', }; function log(msg, color = 'reset') { console.log(`${c[color]}${msg}${c.reset}`); } function logOk(msg) { log(` ✓ ${msg}`, 'green'); } function logWarn(msg) { log(` ⚠ ${msg}`, 'yellow'); } function logErr(msg) { log(` ✗ ${msg}`, 'red'); } // ── Helpers ───────────────────────────────────────────────────────────── function copyDir(src, dest) { mkdirSync(dest, { recursive: true }); for (const entry of readdirSync(src, { withFileTypes: true })) { const s = join(src, entry.name); const d = join(dest, entry.name); if (entry.name === 'node_modules') continue; entry.isDirectory() ? copyDir(s, d) : copyFileSync(s, d); } } // ── Install ───────────────────────────────────────────────────────────── function install() { console.log(''); log('╔══════════════════════════════════════════════╗', 'cyan'); log('║ Yonexus Plugin Installer v0.2.0 ║', 'cyan'); log('╚══════════════════════════════════════════════╝', 'cyan'); console.log(''); // 1. Build log('[1/4] Building...', 'cyan'); execSync('npm install', { cwd: __dirname, stdio: 'inherit' }); execSync('npm run build', { cwd: __dirname, stdio: 'inherit' }); if (!existsSync(SRC_DIST_DIR)) { logErr(`Build output not found at ${SRC_DIST_DIR}`); process.exit(1); } logOk('Build complete'); // 2. Copy to plugins dir log('[2/4] Installing...', 'cyan'); const openclawPath = resolveOpenclawPath(); const destDir = join(openclawPath, 'plugins', PLUGIN_NAME); log(` OpenClaw path: ${openclawPath}`, 'blue'); if (existsSync(destDir)) rmSync(destDir, { recursive: true, force: true }); copyDir(SRC_DIST_DIR, destDir); logOk(`Plugin files → ${destDir}`); // 3. Configure OpenClaw log('[3/4] Configuring OpenClaw...', 'cyan'); try { const pluginPath = destDir; const allow = ensureArray(getConfigValue('plugins.allow')); const loadPaths = ensureArray(getConfigValue('plugins.load.paths')); if (!allow.includes(PLUGIN_NAME)) allow.push(PLUGIN_NAME); if (!loadPaths.includes(pluginPath)) loadPaths.push(pluginPath); execSync(`openclaw config set plugins.allow '${JSON.stringify(allow)}'`); execSync(`openclaw config set plugins.load.paths '${JSON.stringify(loadPaths)}'`); execSync(`openclaw config set plugins.entries.${PLUGIN_NAME}.enabled true`); execSync(`openclaw config set plugins.entries.${PLUGIN_NAME}.config '{"enabled": true}'`); logOk('OpenClaw config updated'); } catch (err) { logErr('Failed to update OpenClaw config via `openclaw config set`'); throw err; } // 4. Summary log('[4/4] Done!', 'cyan'); console.log(''); log('✓ Yonexus installed successfully!', 'green'); console.log(''); log('Next steps:', 'blue'); log(' openclaw gateway restart', 'cyan'); console.log(''); } function getConfigValue(path) { try { const out = execSync(`openclaw config get ${path}`, { encoding: 'utf8' }).trim(); if (!out || out === 'undefined' || out === 'null') return undefined; try { return JSON.parse(out); } catch { return out; } } catch { return undefined; } } function ensureArray(value) { if (Array.isArray(value)) return value; if (value === undefined || value === null || value === '') return []; return [value]; } // ── Uninstall ─────────────────────────────────────────────────────────── function uninstall() { console.log(''); log('Uninstalling Yonexus...', 'cyan'); const openclawPath = resolveOpenclawPath(); const destDir = join(openclawPath, 'plugins', PLUGIN_NAME); if (existsSync(destDir)) { rmSync(destDir, { recursive: true, force: true }); logOk(`Removed ${destDir}`); } else { logWarn(`${destDir} not found, nothing to remove`); } // Clean OpenClaw config log('Cleaning OpenClaw config...', 'cyan'); try { const allow = ensureArray(getConfigValue('plugins.allow')).filter((id) => id !== PLUGIN_NAME); const loadPaths = ensureArray(getConfigValue('plugins.load.paths')).filter((p) => p !== destDir); if (allow.length > 0) { execSync(`openclaw config set plugins.allow '${JSON.stringify(allow)}'`); } else { execSync('openclaw config unset plugins.allow'); } if (loadPaths.length > 0) { execSync(`openclaw config set plugins.load.paths '${JSON.stringify(loadPaths)}'`); } else { execSync('openclaw config unset plugins.load.paths'); } execSync(`openclaw config unset plugins.entries.${PLUGIN_NAME}`); logOk('OpenClaw config cleaned'); } catch (err) { logErr('Failed to clean OpenClaw config via `openclaw config`'); throw err; } console.log(''); log('✓ Yonexus uninstalled.', 'green'); log('\nNext: openclaw gateway restart', 'yellow'); console.log(''); } // ── Main ──────────────────────────────────────────────────────────────── if (!isInstall && !isUninstall) { console.log(''); log('Yonexus Plugin Installer', 'cyan'); console.log(''); log('Usage:', 'blue'); log(' node install.mjs --install Install plugin', 'reset'); log(' node install.mjs --install --openclaw-profile-path Install to custom path', 'reset'); log(' node install.mjs --uninstall Uninstall plugin', 'reset'); log(' node install.mjs --uninstall --openclaw-profile-path Uninstall from custom path', 'reset'); console.log(''); process.exit(1); } if (isInstall) install(); if (isUninstall) uninstall();