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;
}
}