import path from "node:path"; import type { ClawdbotConfig } from "../../../config/config.js"; import { resolveGatewayLaunchAgentLabel } from "../../../daemon/constants.js"; import { resolveGatewayProgramArguments } from "../../../daemon/program-args.js"; import { renderSystemNodeWarning, resolvePreferredNodePath, resolveSystemNodeInfo, } from "../../../daemon/runtime-paths.js"; import { resolveGatewayService } from "../../../daemon/service.js"; import { buildServiceEnvironment } from "../../../daemon/service-env.js"; import { isSystemdUserServiceAvailable } from "../../../daemon/systemd.js"; import type { RuntimeEnv } from "../../../runtime.js"; import { DEFAULT_GATEWAY_DAEMON_RUNTIME, isGatewayDaemonRuntime } from "../../daemon-runtime.js"; import type { OnboardOptions } from "../../onboard-types.js"; import { ensureSystemdUserLingerNonInteractive } from "../../systemd-linger.js"; export async function installGatewayDaemonNonInteractive(params: { nextConfig: ClawdbotConfig; opts: OnboardOptions; runtime: RuntimeEnv; port: number; gatewayToken?: string; }) { const { opts, runtime, port, gatewayToken } = params; if (!opts.installDaemon) return; const daemonRuntimeRaw = opts.daemonRuntime ?? DEFAULT_GATEWAY_DAEMON_RUNTIME; const systemdAvailable = process.platform === "linux" ? await isSystemdUserServiceAvailable() : true; if (process.platform === "linux" && !systemdAvailable) { runtime.log("Systemd user services are unavailable; skipping daemon install."); return; } if (!isGatewayDaemonRuntime(daemonRuntimeRaw)) { runtime.error("Invalid --daemon-runtime (use node or bun)"); runtime.exit(1); return; } const service = resolveGatewayService(); const devMode = process.argv[1]?.includes(`${path.sep}src${path.sep}`) && process.argv[1]?.endsWith(".ts"); const nodePath = await resolvePreferredNodePath({ env: process.env, runtime: daemonRuntimeRaw, }); const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({ port, dev: devMode, runtime: daemonRuntimeRaw, nodePath, }); if (daemonRuntimeRaw === "node") { const systemNode = await resolveSystemNodeInfo({ env: process.env }); const warning = renderSystemNodeWarning(systemNode, programArguments[0]); if (warning) runtime.log(warning); } const environment = buildServiceEnvironment({ env: process.env, port, token: gatewayToken, launchdLabel: process.platform === "darwin" ? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE) : undefined, }); try { await service.install({ env: process.env, stdout: process.stdout, programArguments, workingDirectory, environment, }); } catch (err) { runtime.error(`Gateway daemon install failed: ${String(err)}`); if (process.platform === "win32") { runtime.log( "Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install.", ); } else { runtime.log("Tip: rerun `clawdbot daemon install` after fixing the error."); } return; } await ensureSystemdUserLingerNonInteractive({ runtime }); }