refactor: unify gateway daemon install plan
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
70
src/commands/daemon-install-helpers.ts
Normal file
70
src/commands/daemon-install-helpers.ts
Normal 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.";
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
|||||||
@@ -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",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user