(options: ServiceInstallOptions)
| 69 | // ── macOS (launchd) ─────────────────────────────────────────────────── |
| 70 | |
| 71 | function buildPlist(options: ServiceInstallOptions): string { |
| 72 | const port = options.port ?? 3110 |
| 73 | const host = options.host ?? '127.0.0.1' |
| 74 | const cliEntry = resolveCliPath('bin/chatlab.mjs') |
| 75 | const args = ['start', '--no-open', '--port', String(port), '--host', host] |
| 76 | if (options.token) args.push('--token', options.token) |
| 77 | if (options.headless) args.push('--headless') |
| 78 | if (options.requireAuth) args.push('--require-auth') |
| 79 | |
| 80 | const programArgs = [process.execPath, cliEntry, ...args].map((a) => ` <string>${a}</string>`).join('\n') |
| 81 | |
| 82 | fs.mkdirSync(path.join(SYSTEM_DIR, 'logs'), { recursive: true }) |
| 83 | |
| 84 | return `<?xml version="1.0" encoding="UTF-8"?> |
| 85 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 86 | <plist version="1.0"> |
| 87 | <dict> |
| 88 | <key>Label</key> |
| 89 | <string>${SERVICE_LABEL}</string> |
| 90 | <key>ProgramArguments</key> |
| 91 | <array> |
| 92 | ${programArgs} |
| 93 | </array> |
| 94 | <key>RunAtLoad</key> |
| 95 | <true/> |
| 96 | <key>KeepAlive</key> |
| 97 | <true/> |
| 98 | <key>StandardOutPath</key> |
| 99 | <string>${LOG_FILE}</string> |
| 100 | <key>StandardErrorPath</key> |
| 101 | <string>${LOG_FILE}</string> |
| 102 | </dict> |
| 103 | </plist> |
| 104 | ` |
| 105 | } |
| 106 | |
| 107 | function getUid(): string { |
| 108 | return execSync('id -u', { encoding: 'utf-8' }).trim() |
no test coverage detected