import chalk from 'chalk'; import fs from 'fs/promises'; import path from 'path'; import { execSync } from 'child_process'; import { fileURLToPath } from 'url'; async function execShellCommand(cmd: string) { try { const output = execSync(cmd, { stdio: 'pipe' }).toString(); return output; } catch (error: any) { return error.stderr?.toString() || error.stdout?.toString() || error.message; } } export async function enableDaemon() { console.log(chalk.bold('\n⚙️ Enabling Rigstate Background Service (macOS)\n')); if (process.platform !== 'darwin') { console.error(chalk.red('❌ Currently only macOS is supported for auto-start.')); console.error(chalk.yellow('PRs welcome for Linux/Windows support!')); return; } const homeDir = process.env.HOME || ''; if (!homeDir) { console.error(chalk.red('❌ Could not determine HOME directory.')); return; } const agentsDir = path.join(homeDir, 'Library/LaunchAgents'); const logDir = path.join(homeDir, '.rigstate/logs'); const plistPath = path.join(agentsDir, 'com.rigstate.daemon.plist'); // Ensure directories exist await fs.mkdir(agentsDir, { recursive: true }); await fs.mkdir(logDir, { recursive: true }); const scriptPath = fileURLToPath(import.meta.url); const nodePath = process.execPath; const plistContent = ` Label com.rigstate.daemon ProgramArguments ${nodePath} ${scriptPath} daemon --no-bridge WorkingDirectory ${process.cwd()} StandardOutPath ${path.join(logDir, 'daemon.out.log')} StandardErrorPath ${path.join(logDir, 'daemon.err.log')} RunAtLoad KeepAlive EnvironmentVariables PATH /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${process.env.PATH} `; try { await fs.writeFile(plistPath, plistContent); console.log(chalk.dim(`Created plist at: ${plistPath}`)); try { await execShellCommand(`launchctl unload ${plistPath}`); } catch (e) { } await execShellCommand(`launchctl load ${plistPath}`); console.log(chalk.green('✅ Successfully enabled background daemon!')); console.log(chalk.dim(`Logs: ${logDir}`)); console.log(chalk.dim('The daemon will now restart automatically if it crashes or on reboot.')); } catch (error: any) { console.error(chalk.red('❌ Failed to enable daemon:'), error.message); } } export async function disableDaemon() { console.log(chalk.bold('\n⚙️ Disabling Rigstate Background Service\n')); const homeDir = process.env.HOME || ''; const plistPath = path.join(homeDir, 'Library/LaunchAgents/com.rigstate.daemon.plist'); try { await execShellCommand(`launchctl unload ${plistPath}`); await fs.unlink(plistPath); console.log(chalk.green('✅ Successfully disabled background daemon.')); } catch (error: any) { if (error.code === 'ENOENT') { console.log(chalk.green('✅ Daemon was not enabled.')); } else { console.error(chalk.red('❌ Failed to disable daemon:'), error.message); } } } export async function isDaemonRunning(): Promise { if (process.platform !== 'darwin') return false; try { const output = await execShellCommand('launchctl list com.rigstate.daemon'); return output.includes('"PID" ='); } catch { return false; } }