refactor: unify gateway daemon install plan

This commit is contained in:
Peter Steinberger
2026-01-17 23:29:30 +00:00
parent 5aed38eebc
commit 9de762faa2
7 changed files with 140 additions and 240 deletions

View File

@@ -1,19 +1,11 @@
import path from "node:path";
import { import {
DEFAULT_GATEWAY_DAEMON_RUNTIME, DEFAULT_GATEWAY_DAEMON_RUNTIME,
isGatewayDaemonRuntime, isGatewayDaemonRuntime,
} from "../../commands/daemon-runtime.js"; } from "../../commands/daemon-runtime.js";
import { buildGatewayInstallPlan } from "../../commands/daemon-install-helpers.js";
import { loadConfig, resolveGatewayPort } from "../../config/config.js"; import { loadConfig, resolveGatewayPort } from "../../config/config.js";
import { resolveIsNixMode } from "../../config/paths.js"; import { resolveIsNixMode } from "../../config/paths.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 { resolveGatewayService } from "../../daemon/service.js";
import { buildServiceEnvironment } from "../../daemon/service-env.js";
import { defaultRuntime } from "../../runtime.js"; import { defaultRuntime } from "../../runtime.js";
import { buildDaemonServiceSnapshot, createNullWriter, emitDaemonActionJson } from "./response.js"; import { buildDaemonServiceSnapshot, createNullWriter, emitDaemonActionJson } from "./response.js";
import { parsePort } from "./shared.js"; import { parsePort } from "./shared.js";
@@ -96,34 +88,15 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) {
} }
} }
const devMode = const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
process.argv[1]?.includes(`${path.sep}src${path.sep}`) && process.argv[1]?.endsWith(".ts");
const nodePath = await resolvePreferredNodePath({
env: process.env,
runtime: runtimeRaw,
});
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port,
dev: devMode,
runtime: runtimeRaw,
nodePath,
});
if (runtimeRaw === "node") {
const systemNode = await resolveSystemNodeInfo({ env: process.env });
const warning = renderSystemNodeWarning(systemNode, programArguments[0]);
if (warning) {
if (json) warnings.push(warning);
else defaultRuntime.log(warning);
}
}
const environment = buildServiceEnvironment({
env: process.env, env: process.env,
port, port,
token: opts.token || cfg.gateway?.auth?.token || process.env.CLAWDBOT_GATEWAY_TOKEN, token: opts.token || cfg.gateway?.auth?.token || process.env.CLAWDBOT_GATEWAY_TOKEN,
launchdLabel: runtime: runtimeRaw,
process.platform === "darwin" warn: (message) => {
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE) if (json) warnings.push(message);
: undefined, else defaultRuntime.log(message);
},
}); });
try { try {

View File

@@ -1,13 +1,5 @@
import path from "node:path"; import { buildGatewayInstallPlan, gatewayInstallErrorHint } from "./daemon-install-helpers.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 { resolveGatewayService } from "../daemon/service.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import { withProgress } from "../cli/progress.js"; import { withProgress } from "../cli/progress.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js"; import { note } from "../terminal/note.js";
@@ -89,32 +81,12 @@ export async function maybeInstallDaemon(params: {
progress.setLabel("Preparing Gateway daemon…"); progress.setLabel("Preparing Gateway daemon…");
const devMode = const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
process.argv[1]?.includes(`${path.sep}src${path.sep}`) &&
process.argv[1]?.endsWith(".ts");
const nodePath = await resolvePreferredNodePath({
env: process.env,
runtime: daemonRuntime,
});
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port: params.port,
dev: devMode,
runtime: daemonRuntime,
nodePath,
});
if (daemonRuntime === "node") {
const systemNode = await resolveSystemNodeInfo({ env: process.env });
const warning = renderSystemNodeWarning(systemNode, programArguments[0]);
if (warning) note(warning, "Gateway runtime");
}
const environment = buildServiceEnvironment({
env: process.env, env: process.env,
port: params.port, port: params.port,
token: params.gatewayToken, token: params.gatewayToken,
launchdLabel: runtime: daemonRuntime,
process.platform === "darwin" warn: (message, title) => note(message, title),
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
}); });
progress.setLabel("Installing Gateway daemon…"); progress.setLabel("Installing Gateway daemon…");
@@ -135,14 +107,7 @@ export async function maybeInstallDaemon(params: {
); );
if (installError) { if (installError) {
note("Gateway daemon install failed: " + installError, "Gateway"); note("Gateway daemon install failed: " + installError, "Gateway");
if (process.platform === "win32") { note(gatewayInstallErrorHint(), "Gateway");
note(
"Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install.",
"Gateway",
);
} else {
note("Tip: rerun `clawdbot daemon install` after fixing the error.", "Gateway");
}
return; return;
} }
shouldCheckLinger = true; shouldCheckLinger = true;

View File

@@ -0,0 +1,70 @@
import path from "node:path";
import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
import { resolveGatewayProgramArguments } from "../daemon/program-args.js";
import {
renderSystemNodeWarning,
resolvePreferredNodePath,
resolveSystemNodeInfo,
} from "../daemon/runtime-paths.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import type { GatewayDaemonRuntime } from "./daemon-runtime.js";
type WarnFn = (message: string, title?: string) => void;
export type GatewayInstallPlan = {
programArguments: string[];
workingDirectory?: string;
environment: Record<string, string | undefined>;
};
export function resolveGatewayDevMode(argv: string[] = process.argv): boolean {
const entry = argv[1];
return Boolean(entry?.includes(`${path.sep}src${path.sep}`) && entry.endsWith(".ts"));
}
export async function buildGatewayInstallPlan(params: {
env: Record<string, string | undefined>;
port: number;
runtime: GatewayDaemonRuntime;
token?: string;
devMode?: boolean;
nodePath?: string;
warn?: WarnFn;
}): Promise<GatewayInstallPlan> {
const devMode = params.devMode ?? resolveGatewayDevMode();
const nodePath =
params.nodePath ??
(await resolvePreferredNodePath({
env: params.env,
runtime: params.runtime,
}));
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port: params.port,
dev: devMode,
runtime: params.runtime,
nodePath,
});
if (params.runtime === "node") {
const systemNode = await resolveSystemNodeInfo({ env: params.env });
const warning = renderSystemNodeWarning(systemNode, programArguments[0]);
if (warning) params.warn?.(warning, "Gateway runtime");
}
const environment = buildServiceEnvironment({
env: params.env,
port: params.port,
token: params.token,
launchdLabel:
process.platform === "darwin"
? resolveGatewayLaunchAgentLabel(params.env.CLAWDBOT_PROFILE)
: undefined,
});
return { programArguments, workingDirectory, environment };
}
export function gatewayInstallErrorHint(platform = process.platform): string {
return platform === "win32"
? "Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install."
: "Tip: rerun `clawdbot daemon install` after fixing the error.";
}

View File

@@ -1,17 +1,7 @@
import path from "node:path";
import type { ClawdbotConfig } from "../config/config.js"; import type { ClawdbotConfig } from "../config/config.js";
import { resolveGatewayPort } from "../config/config.js"; import { resolveGatewayPort } from "../config/config.js";
import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
import { readLastGatewayErrorLine } from "../daemon/diagnostics.js"; import { readLastGatewayErrorLine } from "../daemon/diagnostics.js";
import { resolveGatewayProgramArguments } from "../daemon/program-args.js";
import {
renderSystemNodeWarning,
resolvePreferredNodePath,
resolveSystemNodeInfo,
} from "../daemon/runtime-paths.js";
import { resolveGatewayService } from "../daemon/service.js"; import { resolveGatewayService } from "../daemon/service.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import { isSystemdUserServiceAvailable } from "../daemon/systemd.js"; import { isSystemdUserServiceAvailable } from "../daemon/systemd.js";
import { renderSystemdUnavailableHints } from "../daemon/systemd-hints.js"; import { renderSystemdUnavailableHints } from "../daemon/systemd-hints.js";
import { formatPortDiagnostics, inspectPortUsage } from "../infra/ports.js"; import { formatPortDiagnostics, inspectPortUsage } from "../infra/ports.js";
@@ -24,6 +14,10 @@ import {
GATEWAY_DAEMON_RUNTIME_OPTIONS, GATEWAY_DAEMON_RUNTIME_OPTIONS,
type GatewayDaemonRuntime, type GatewayDaemonRuntime,
} from "./daemon-runtime.js"; } from "./daemon-runtime.js";
import {
buildGatewayInstallPlan,
gatewayInstallErrorHint,
} from "./daemon-install-helpers.js";
import { buildGatewayRuntimeHints, formatGatewayRuntimeSummary } from "./doctor-format.js"; import { buildGatewayRuntimeHints, formatGatewayRuntimeSummary } from "./doctor-format.js";
import type { DoctorOptions, DoctorPrompter } from "./doctor-prompter.js"; import type { DoctorOptions, DoctorPrompter } from "./doctor-prompter.js";
import { healthCommand } from "./health.js"; import { healthCommand } from "./health.js";
@@ -81,41 +75,26 @@ export async function maybeRepairGatewayDaemon(params: {
}, },
DEFAULT_GATEWAY_DAEMON_RUNTIME, DEFAULT_GATEWAY_DAEMON_RUNTIME,
); );
const devMode =
process.argv[1]?.includes(`${path.sep}src${path.sep}`) &&
process.argv[1]?.endsWith(".ts");
const port = resolveGatewayPort(params.cfg, process.env); const port = resolveGatewayPort(params.cfg, process.env);
const nodePath = await resolvePreferredNodePath({ const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
env: process.env,
runtime: daemonRuntime,
});
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port,
dev: devMode,
runtime: daemonRuntime,
nodePath,
});
if (daemonRuntime === "node") {
const systemNode = await resolveSystemNodeInfo({ env: process.env });
const warning = renderSystemNodeWarning(systemNode, programArguments[0]);
if (warning) note(warning, "Gateway runtime");
}
const environment = buildServiceEnvironment({
env: process.env, env: process.env,
port, port,
token: params.cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN, token: params.cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN,
launchdLabel: runtime: daemonRuntime,
process.platform === "darwin" warn: (message, title) => note(message, title),
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
});
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
}); });
try {
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
});
} catch (err) {
note(`Gateway daemon install failed: ${String(err)}`, "Gateway");
note(gatewayInstallErrorHint(), "Gateway");
}
} }
} }
return; return;

View File

@@ -2,13 +2,10 @@ import path from "node:path";
import type { ClawdbotConfig } from "../config/config.js"; import type { ClawdbotConfig } from "../config/config.js";
import { resolveGatewayPort, resolveIsNixMode } from "../config/paths.js"; import { resolveGatewayPort, resolveIsNixMode } from "../config/paths.js";
import { resolveGatewayLaunchAgentLabel } from "../daemon/constants.js";
import { findExtraGatewayServices, renderGatewayServiceCleanupHints } from "../daemon/inspect.js"; import { findExtraGatewayServices, renderGatewayServiceCleanupHints } from "../daemon/inspect.js";
import { findLegacyGatewayServices, uninstallLegacyGatewayServices } from "../daemon/legacy.js"; import { findLegacyGatewayServices, uninstallLegacyGatewayServices } from "../daemon/legacy.js";
import { resolveGatewayProgramArguments } from "../daemon/program-args.js";
import { import {
renderSystemNodeWarning, renderSystemNodeWarning,
resolvePreferredNodePath,
resolveSystemNodeInfo, resolveSystemNodeInfo,
} from "../daemon/runtime-paths.js"; } from "../daemon/runtime-paths.js";
import { resolveGatewayService } from "../daemon/service.js"; import { resolveGatewayService } from "../daemon/service.js";
@@ -17,9 +14,12 @@ import {
needsNodeRuntimeMigration, needsNodeRuntimeMigration,
SERVICE_AUDIT_CODES, SERVICE_AUDIT_CODES,
} from "../daemon/service-audit.js"; } from "../daemon/service-audit.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js"; import { note } from "../terminal/note.js";
import {
buildGatewayInstallPlan,
gatewayInstallErrorHint,
} from "./daemon-install-helpers.js";
import { import {
DEFAULT_GATEWAY_DAEMON_RUNTIME, DEFAULT_GATEWAY_DAEMON_RUNTIME,
GATEWAY_DAEMON_RUNTIME_OPTIONS, GATEWAY_DAEMON_RUNTIME_OPTIONS,
@@ -109,35 +109,26 @@ export async function maybeMigrateLegacyGatewayService(
}, },
DEFAULT_GATEWAY_DAEMON_RUNTIME, DEFAULT_GATEWAY_DAEMON_RUNTIME,
); );
const devMode =
process.argv[1]?.includes(`${path.sep}src${path.sep}`) && process.argv[1]?.endsWith(".ts");
const port = resolveGatewayPort(cfg, process.env); const port = resolveGatewayPort(cfg, process.env);
const nodePath = await resolvePreferredNodePath({ const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
env: process.env,
runtime: daemonRuntime,
});
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port,
dev: devMode,
runtime: daemonRuntime,
nodePath,
});
const environment = buildServiceEnvironment({
env: process.env, env: process.env,
port, port,
token: cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN, token: cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN,
launchdLabel: runtime: daemonRuntime,
process.platform === "darwin" warn: (message, title) => note(message, title),
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
});
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
}); });
try {
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
});
} catch (err) {
runtime.error(`Gateway daemon install failed: ${String(err)}`);
note(gatewayInstallErrorHint(), "Gateway");
}
} }
export async function maybeRepairGatewayServiceConfig( export async function maybeRepairGatewayServiceConfig(
@@ -183,15 +174,15 @@ export async function maybeRepairGatewayServiceConfig(
); );
} }
const devMode =
process.argv[1]?.includes(`${path.sep}src${path.sep}`) && process.argv[1]?.endsWith(".ts");
const port = resolveGatewayPort(cfg, process.env); const port = resolveGatewayPort(cfg, process.env);
const runtimeChoice = detectGatewayRuntime(command.programArguments); const runtimeChoice = detectGatewayRuntime(command.programArguments);
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({ const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
env: process.env,
port, port,
dev: devMode, token: cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN,
runtime: needsNodeRuntime && systemNodePath ? "node" : runtimeChoice, runtime: needsNodeRuntime && systemNodePath ? "node" : runtimeChoice,
nodePath: systemNodePath ?? undefined, nodePath: systemNodePath ?? undefined,
warn: (message, title) => note(message, title),
}); });
const expectedEntrypoint = findGatewayEntrypoint(programArguments); const expectedEntrypoint = findGatewayEntrypoint(programArguments);
const currentEntrypoint = findGatewayEntrypoint(command.programArguments); const currentEntrypoint = findGatewayEntrypoint(command.programArguments);
@@ -239,16 +230,6 @@ export async function maybeRepairGatewayServiceConfig(
initialValue: true, initialValue: true,
}); });
if (!repair) return; if (!repair) return;
const environment = buildServiceEnvironment({
env: process.env,
port,
token: cfg.gateway?.auth?.token ?? process.env.CLAWDBOT_GATEWAY_TOKEN,
launchdLabel:
process.platform === "darwin"
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
});
try { try {
await service.install({ await service.install({
env: process.env, env: process.env,

View File

@@ -1,18 +1,12 @@
import path from "node:path";
import type { ClawdbotConfig } from "../../../config/config.js"; 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 { resolveGatewayService } from "../../../daemon/service.js";
import { buildServiceEnvironment } from "../../../daemon/service-env.js";
import { isSystemdUserServiceAvailable } from "../../../daemon/systemd.js"; import { isSystemdUserServiceAvailable } from "../../../daemon/systemd.js";
import type { RuntimeEnv } from "../../../runtime.js"; import type { RuntimeEnv } from "../../../runtime.js";
import { DEFAULT_GATEWAY_DAEMON_RUNTIME, isGatewayDaemonRuntime } from "../../daemon-runtime.js"; import { DEFAULT_GATEWAY_DAEMON_RUNTIME, isGatewayDaemonRuntime } from "../../daemon-runtime.js";
import {
buildGatewayInstallPlan,
gatewayInstallErrorHint,
} from "../../daemon-install-helpers.js";
import type { OnboardOptions } from "../../onboard-types.js"; import type { OnboardOptions } from "../../onboard-types.js";
import { ensureSystemdUserLingerNonInteractive } from "../../systemd-linger.js"; import { ensureSystemdUserLingerNonInteractive } from "../../systemd-linger.js";
@@ -41,33 +35,12 @@ export async function installGatewayDaemonNonInteractive(params: {
} }
const service = resolveGatewayService(); const service = resolveGatewayService();
const devMode = const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
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, env: process.env,
port, port,
token: gatewayToken, token: gatewayToken,
launchdLabel: runtime: daemonRuntimeRaw,
process.platform === "darwin" warn: (message) => runtime.log(message),
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
}); });
try { try {
await service.install({ await service.install({
@@ -79,13 +52,7 @@ export async function installGatewayDaemonNonInteractive(params: {
}); });
} catch (err) { } catch (err) {
runtime.error(`Gateway daemon install failed: ${String(err)}`); runtime.error(`Gateway daemon install failed: ${String(err)}`);
if (process.platform === "win32") { runtime.log(gatewayInstallErrorHint());
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; return;
} }
await ensureSystemdUserLingerNonInteractive({ runtime }); await ensureSystemdUserLingerNonInteractive({ runtime });

View File

@@ -1,6 +1,4 @@
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path";
import { DEFAULT_BOOTSTRAP_FILENAME } from "../agents/workspace.js"; import { DEFAULT_BOOTSTRAP_FILENAME } from "../agents/workspace.js";
import { import {
DEFAULT_GATEWAY_DAEMON_RUNTIME, DEFAULT_GATEWAY_DAEMON_RUNTIME,
@@ -19,20 +17,16 @@ import {
} from "../commands/onboard-helpers.js"; } from "../commands/onboard-helpers.js";
import type { OnboardOptions } from "../commands/onboard-types.js"; import type { OnboardOptions } from "../commands/onboard-types.js";
import type { ClawdbotConfig } from "../config/config.js"; 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 { resolveGatewayService } from "../daemon/service.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import { isSystemdUserServiceAvailable } from "../daemon/systemd.js"; import { isSystemdUserServiceAvailable } from "../daemon/systemd.js";
import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js"; import { ensureControlUiAssetsBuilt } from "../infra/control-ui-assets.js";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import { runTui } from "../tui/tui.js"; import { runTui } from "../tui/tui.js";
import { resolveUserPath } from "../utils.js"; import { resolveUserPath } from "../utils.js";
import {
buildGatewayInstallPlan,
gatewayInstallErrorHint,
} from "../commands/daemon-install-helpers.js";
import type { GatewayWizardSettings, WizardFlow } from "./onboarding.types.js"; import type { GatewayWizardSettings, WizardFlow } from "./onboarding.types.js";
import type { WizardPrompter } from "./prompts.js"; import type { WizardPrompter } from "./prompts.js";
@@ -161,35 +155,16 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption
} }
if (!loaded || (loaded && (await service.isLoaded({ env: process.env })) === false)) { if (!loaded || (loaded && (await service.isLoaded({ env: process.env })) === false)) {
const devMode =
process.argv[1]?.includes(`${path.sep}src${path.sep}`) && process.argv[1]?.endsWith(".ts");
const progress = prompter.progress("Gateway daemon"); const progress = prompter.progress("Gateway daemon");
let installError: string | null = null; let installError: string | null = null;
try { try {
progress.update("Preparing Gateway daemon…"); progress.update("Preparing Gateway daemon…");
const nodePath = await resolvePreferredNodePath({ const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
env: process.env,
runtime: daemonRuntime,
});
const { programArguments, workingDirectory } = await resolveGatewayProgramArguments({
port: settings.port,
dev: devMode,
runtime: daemonRuntime,
nodePath,
});
if (daemonRuntime === "node") {
const systemNode = await resolveSystemNodeInfo({ env: process.env });
const warning = renderSystemNodeWarning(systemNode, programArguments[0]);
if (warning) await prompter.note(warning, "Gateway runtime");
}
const environment = buildServiceEnvironment({
env: process.env, env: process.env,
port: settings.port, port: settings.port,
token: settings.gatewayToken, token: settings.gatewayToken,
launchdLabel: runtime: daemonRuntime,
process.platform === "darwin" warn: (message, title) => prompter.note(message, title),
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
}); });
progress.update("Installing Gateway daemon…"); progress.update("Installing Gateway daemon…");
@@ -207,17 +182,7 @@ export async function finalizeOnboardingWizard(options: FinalizeOnboardingOption
} }
if (installError) { if (installError) {
await prompter.note(`Gateway daemon install failed: ${installError}`, "Gateway"); await prompter.note(`Gateway daemon install failed: ${installError}`, "Gateway");
if (process.platform === "win32") { await prompter.note(gatewayInstallErrorHint(), "Gateway");
await prompter.note(
"Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip daemon install.",
"Gateway",
);
} else {
await prompter.note(
"Tip: rerun `clawdbot daemon install` after fixing the error.",
"Gateway",
);
}
} }
} }
} }