- Move src/ → plugin/ with subdirectories: - plugin/core/ (business logic, models, store, permissions, utils, memory) - plugin/tools/ (query, resources) - plugin/commands/ (placeholder for slash commands) - plugin/hooks/ (placeholder for lifecycle hooks) - plugin/index.ts (wiring layer only, no business logic) - Add install.mjs with --install, --uninstall, --openclaw-profile-path - Add skills/ and docs/ root directories - Move planning docs (PLAN.md, FEAT.md, AGENT_TASKS.md) to docs/ - Remove old scripts/install.sh - Update tsconfig rootDir: src → plugin - Update README.md and README.zh.md with new layout - Bump version to 0.2.0 - All tests pass
146 lines
5.6 KiB
JavaScript
146 lines
5.6 KiB
JavaScript
#!/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/3] 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/3] 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. Summary
|
|
log('[3/3] Done!', 'cyan');
|
|
console.log('');
|
|
log('✓ Yonexus installed successfully!', 'green');
|
|
console.log('');
|
|
log('Next steps:', 'blue');
|
|
log(' openclaw gateway restart', 'cyan');
|
|
console.log('');
|
|
}
|
|
|
|
// ── 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`);
|
|
}
|
|
|
|
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 <path> Install to custom path', 'reset');
|
|
log(' node install.mjs --uninstall Uninstall plugin', 'reset');
|
|
log(' node install.mjs --uninstall --openclaw-profile-path <path> Uninstall from custom path', 'reset');
|
|
console.log('');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (isInstall) install();
|
|
if (isUninstall) uninstall();
|