/** * ZCLAW Setup Script * * First-time setup for ZCLAW: * 1. Check if OpenClaw is installed * 2. Copy default config files to ~/.openclaw/ * 3. Register ZCLAW custom plugins * 4. Create workspace directory */ import { execSync, exec } from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; const OPENCLAW_HOME = process.env.OPENCLAW_HOME || path.join( process.env.HOME || process.env.USERPROFILE || '', '.openclaw' ); const ZCLAW_ROOT = path.resolve(__dirname, '..'); function uniqueStrings(values: string[]): string[] { return Array.from(new Set(values.filter(Boolean))); } function resolveRepoPaths(values: string[] | undefined): string[] { return (values || []).map((p) => path.resolve(ZCLAW_ROOT, p)); } function log(msg: string) { console.log(`[ZCLAW Setup] ${msg}`); } function error(msg: string) { console.error(`[ZCLAW Setup] ❌ ${msg}`); } function success(msg: string) { console.log(`[ZCLAW Setup] ✅ ${msg}`); } // Step 1: Check OpenClaw installation function checkOpenClaw(): boolean { try { const version = execSync('openclaw --version', { encoding: 'utf-8' }).trim(); success(`OpenClaw found: ${version}`); return true; } catch { error('OpenClaw not found. Please install it first:'); console.log(' Windows: iwr -useb https://openclaw.ai/install.ps1 | iex'); console.log(' macOS/Linux: curl -fsSL https://openclaw.ai/install.sh | bash'); console.log(' npm: npm install -g openclaw@latest'); return false; } } // Step 2: Copy default config function setupConfig() { const configDir = OPENCLAW_HOME; const configFile = path.join(configDir, 'openclaw.json'); const defaultConfigPath = path.join(ZCLAW_ROOT, 'config', 'openclaw.default.json'); fs.mkdirSync(configDir, { recursive: true }); const defaultConfig = JSON.parse(fs.readFileSync(defaultConfigPath, 'utf-8')); const config = fs.existsSync(configFile) ? JSON.parse(fs.readFileSync(configFile, 'utf-8')) : defaultConfig; const defaultPluginPaths = resolveRepoPaths(defaultConfig.plugins?.load?.paths); const existingPluginPaths = Array.isArray(config.plugins?.load?.paths) ? config.plugins.load.paths : []; const mergedPluginPaths = uniqueStrings([...existingPluginPaths, ...defaultPluginPaths]); const defaultSkillDirs = resolveRepoPaths(defaultConfig.skills?.load?.extraDirs); const existingSkillDirs = Array.isArray(config.skills?.load?.extraDirs) ? config.skills.load.extraDirs : []; const mergedSkillDirs = uniqueStrings([...existingSkillDirs, ...defaultSkillDirs]); config.plugins = config.plugins || {}; config.plugins.load = config.plugins.load || {}; config.plugins.load.paths = mergedPluginPaths; config.skills = config.skills || {}; config.skills.load = config.skills.load || {}; config.skills.load.extraDirs = mergedSkillDirs; fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf-8'); success(fs.existsSync(configFile) ? `Config updated at ${configFile}` : `Config written to ${configFile}`); // Copy bootstrap files const bootstrapFiles = ['SOUL.md', 'AGENTS.md', 'IDENTITY.md', 'USER.md']; const workspaceDir = path.join(configDir, 'zclaw-workspace'); fs.mkdirSync(workspaceDir, { recursive: true }); for (const file of bootstrapFiles) { const src = path.join(ZCLAW_ROOT, 'config', file); const dest = path.join(workspaceDir, file); if (fs.existsSync(src) && !fs.existsSync(dest)) { fs.copyFileSync(src, dest); success(`Bootstrap file copied: ${file}`); } } } // Step 3: Register plugins function registerPlugins() { const pluginDirs = ['zclaw-chinese-models', 'zclaw-feishu', 'zclaw-ui']; for (const plugin of pluginDirs) { const pluginPath = path.join(ZCLAW_ROOT, 'plugins', plugin); if (fs.existsSync(pluginPath)) { try { // Use openclaw plugins install -l (link mode) for development execSync(`openclaw plugins install -l "${pluginPath}"`, { encoding: 'utf-8', stdio: 'pipe' }); success(`Plugin linked: ${plugin}`); } catch (err: any) { // Plugin might already be registered, or command format different log(`Plugin ${plugin} registration note: ${err.message?.split('\n')[0] || 'check manually'}`); } } } } // Step 4: Create workspace function setupWorkspace() { const workspace = path.join(OPENCLAW_HOME, 'zclaw-workspace'); const dirs = ['skills', 'output', 'context']; for (const dir of dirs) { const fullPath = path.join(workspace, dir); fs.mkdirSync(fullPath, { recursive: true }); } success(`Workspace ready at ${workspace}`); } // Main async function main() { console.log(''); console.log('🦞 ZCLAW Setup'); console.log('─'.repeat(40)); console.log(''); // Step 1 log('Checking OpenClaw installation...'); const hasOpenClaw = checkOpenClaw(); if (!hasOpenClaw) { console.log(''); console.log('Install OpenClaw first, then re-run this setup.'); process.exit(1); } // Step 2 console.log(''); log('Setting up configuration...'); setupConfig(); // Step 3 console.log(''); log('Registering plugins...'); registerPlugins(); // Step 4 console.log(''); log('Setting up workspace...'); setupWorkspace(); console.log(''); console.log('─'.repeat(40)); success('ZCLAW setup complete!'); console.log(''); console.log('Next steps:'); console.log(' 1. Configure API keys: openclaw configure'); console.log(' 2. Start gateway: openclaw gateway'); console.log(' 3. Launch ZCLAW desktop: cd desktop && pnpm tauri dev'); console.log(''); } main().catch((err) => { error(`Setup failed: ${err.message}`); process.exit(1); });