From 9e22f019db0c4a7952e808a53d95f3d394d40c61 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 21 Jan 2026 17:45:06 +0000 Subject: [PATCH] feat: fold gateway service commands into gateway --- src/agents/system-prompt.test.ts | 2 +- src/agents/system-prompt.ts | 10 +-- src/cli/daemon-cli/install.ts | 4 +- src/cli/daemon-cli/lifecycle.ts | 4 +- src/cli/daemon-cli/register.ts | 6 +- src/cli/daemon-cli/shared.ts | 4 +- src/cli/daemon-cli/status.print.ts | 12 +-- src/cli/daemon-cli/status.ts | 2 +- src/cli/gateway-cli.coverage.test.ts | 6 +- src/cli/gateway-cli/register.ts | 78 +++++++++++++++++-- src/cli/gateway-cli/run.ts | 2 +- src/cli/gateway-cli/shared.ts | 8 +- src/cli/program/config-guard.ts | 22 +++++- src/cli/program/register.subclis.ts | 8 -- src/cli/update-cli.ts | 16 ++-- src/commands/configure.daemon.ts | 26 +++---- src/commands/configure.wizard.ts | 4 +- src/commands/daemon-install-helpers.test.ts | 2 +- src/commands/daemon-install-helpers.ts | 4 +- src/commands/doctor-format.ts | 4 +- src/commands/doctor-gateway-daemon-flow.ts | 14 ++-- src/commands/doctor-gateway-services.ts | 4 +- .../local/daemon-install.ts | 4 +- src/commands/status.command.ts | 2 +- src/commands/uninstall.ts | 2 +- src/daemon/systemd-hints.ts | 2 +- src/infra/ports-format.ts | 2 +- 27 files changed, 166 insertions(+), 88 deletions(-) diff --git a/src/agents/system-prompt.test.ts b/src/agents/system-prompt.test.ts index c9b225830..fce27677a 100644 --- a/src/agents/system-prompt.test.ts +++ b/src/agents/system-prompt.test.ts @@ -66,7 +66,7 @@ describe("buildAgentSystemPrompt", () => { }); expect(prompt).toContain("## Clawdbot CLI Quick Reference"); - expect(prompt).toContain("clawdbot daemon restart"); + expect(prompt).toContain("clawdbot gateway restart"); expect(prompt).toContain("Do not invent commands"); }); diff --git a/src/agents/system-prompt.ts b/src/agents/system-prompt.ts index cb63eb7ec..889ae84f4 100644 --- a/src/agents/system-prompt.ts +++ b/src/agents/system-prompt.ts @@ -365,11 +365,11 @@ export function buildAgentSystemPrompt(params: { "## Clawdbot CLI Quick Reference", "Clawdbot is controlled via subcommands. Do not invent commands.", "To manage the Gateway daemon service (start/stop/restart):", - "- clawdbot daemon status", - "- clawdbot daemon start", - "- clawdbot daemon stop", - "- clawdbot daemon restart", - "If unsure, ask the user to run `clawdbot help` (or `clawdbot daemon --help`) and paste the output.", + "- clawdbot gateway status", + "- clawdbot gateway start", + "- clawdbot gateway stop", + "- clawdbot gateway restart", + "If unsure, ask the user to run `clawdbot help` (or `clawdbot gateway --help`) and paste the output.", "", ...skillsSection, ...memorySection, diff --git a/src/cli/daemon-cli/install.ts b/src/cli/daemon-cli/install.ts index cf852fd38..6f1998d5d 100644 --- a/src/cli/daemon-cli/install.ts +++ b/src/cli/daemon-cli/install.ts @@ -43,7 +43,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) { }; if (resolveIsNixMode(process.env)) { - fail("Nix mode detected; daemon install is disabled."); + fail("Nix mode detected; service install is disabled."); return; } @@ -84,7 +84,7 @@ export async function runDaemonInstall(opts: DaemonInstallOptions) { if (!json) { defaultRuntime.log(`Gateway service already ${service.loadedText}.`); defaultRuntime.log( - `Reinstall with: ${formatCliCommand("clawdbot daemon install --force")}`, + `Reinstall with: ${formatCliCommand("clawdbot gateway install --force")}`, ); } return; diff --git a/src/cli/daemon-cli/lifecycle.ts b/src/cli/daemon-cli/lifecycle.ts index 0ad05f9f7..d5008c2d0 100644 --- a/src/cli/daemon-cli/lifecycle.ts +++ b/src/cli/daemon-cli/lifecycle.ts @@ -33,7 +33,7 @@ export async function runDaemonUninstall(opts: DaemonLifecycleOptions = {}) { }; if (resolveIsNixMode(process.env)) { - fail("Nix mode detected; daemon uninstall is disabled."); + fail("Nix mode detected; service uninstall is disabled."); return; } @@ -200,7 +200,7 @@ export async function runDaemonStop(opts: DaemonLifecycleOptions = {}) { } /** - * Restart the gateway daemon service. + * Restart the gateway service service. * @returns `true` if restart succeeded, `false` if the service was not loaded. * Throws/exits on check or restart failures. */ diff --git a/src/cli/daemon-cli/register.ts b/src/cli/daemon-cli/register.ts index ed37dc841..92b47690d 100644 --- a/src/cli/daemon-cli/register.ts +++ b/src/cli/daemon-cli/register.ts @@ -14,16 +14,16 @@ import { export function registerDaemonCli(program: Command) { const daemon = program .command("daemon") - .description("Manage the Gateway daemon service (launchd/systemd/schtasks)") + .description("Manage the Gateway service (launchd/systemd/schtasks)") .addHelpText( "after", () => - `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/daemon", "docs.clawd.bot/cli/daemon")}\n`, + `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/gateway", "docs.clawd.bot/cli/gateway")}\n`, ); daemon .command("status") - .description("Show daemon install status + probe the Gateway") + .description("Show service install status + probe the Gateway") .option("--url ", "Gateway WebSocket URL (defaults to config/remote/local)") .option("--token ", "Gateway token (if required)") .option("--password ", "Gateway password (password auth)") diff --git a/src/cli/daemon-cli/shared.ts b/src/cli/daemon-cli/shared.ts index 807cf687a..7be597ac5 100644 --- a/src/cli/daemon-cli/shared.ts +++ b/src/cli/daemon-cli/shared.ts @@ -123,7 +123,7 @@ export function renderRuntimeHints( } })(); if (runtime.missingUnit) { - hints.push(`Service not installed. Run: ${formatCliCommand("clawdbot daemon install", env)}`); + hints.push(`Service not installed. Run: ${formatCliCommand("clawdbot gateway install", env)}`); if (fileLog) hints.push(`File logs: ${fileLog}`); return hints; } @@ -146,7 +146,7 @@ export function renderRuntimeHints( export function renderGatewayServiceStartHints(env: NodeJS.ProcessEnv = process.env): string[] { const base = [ - formatCliCommand("clawdbot daemon install", env), + formatCliCommand("clawdbot gateway install", env), formatCliCommand("clawdbot gateway", env), ]; const profile = env.CLAWDBOT_PROFILE; diff --git a/src/cli/daemon-cli/status.print.ts b/src/cli/daemon-cli/status.print.ts index b4e879666..eb7f9f500 100644 --- a/src/cli/daemon-cli/status.print.ts +++ b/src/cli/daemon-cli/status.print.ts @@ -60,7 +60,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) } const daemonEnvLines = safeDaemonEnv(service.command?.environment); if (daemonEnvLines.length > 0) { - defaultRuntime.log(`${label("Daemon env:")} ${daemonEnvLines.join(" ")}`); + defaultRuntime.log(`${label("Service env:")} ${daemonEnvLines.join(" ")}`); } spacer(); @@ -89,11 +89,11 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) } if (status.config.daemon) { const daemonCfg = `${status.config.daemon.path}${status.config.daemon.exists ? "" : " (missing)"}${status.config.daemon.valid ? "" : " (invalid)"}`; - defaultRuntime.log(`${label("Config (daemon):")} ${infoText(daemonCfg)}`); + defaultRuntime.log(`${label("Config (service):")} ${infoText(daemonCfg)}`); if (!status.config.daemon.valid && status.config.daemon.issues?.length) { for (const issue of status.config.daemon.issues.slice(0, 5)) { defaultRuntime.error( - `${errorText("Daemon config issue:")} ${issue.path || ""}: ${issue.message}`, + `${errorText("Service config issue:")} ${issue.path || ""}: ${issue.message}`, ); } } @@ -101,12 +101,12 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) if (status.config.mismatch) { defaultRuntime.error( errorText( - "Root cause: CLI and daemon are using different config paths (likely a profile/state-dir mismatch).", + "Root cause: CLI and service are using different config paths (likely a profile/state-dir mismatch).", ), ); defaultRuntime.error( errorText( - `Fix: rerun \`${formatCliCommand("clawdbot daemon install --force")}\` from the same --profile / CLAWDBOT_STATE_DIR you expect.`, + `Fix: rerun \`${formatCliCommand("clawdbot gateway install --force")}\` from the same --profile / CLAWDBOT_STATE_DIR you expect.`, ), ); } @@ -209,7 +209,7 @@ export function printDaemonStatus(status: DaemonStatus, opts: { json: boolean }) ), ); defaultRuntime.error( - errorText(`Then reinstall: ${formatCliCommand("clawdbot daemon install")}`), + errorText(`Then reinstall: ${formatCliCommand("clawdbot gateway install")}`), ); spacer(); } diff --git a/src/cli/daemon-cli/status.ts b/src/cli/daemon-cli/status.ts index 630369571..2af5a1977 100644 --- a/src/cli/daemon-cli/status.ts +++ b/src/cli/daemon-cli/status.ts @@ -14,7 +14,7 @@ export async function runDaemonStatus(opts: DaemonStatusOptions) { printDaemonStatus(status, { json: Boolean(opts.json) }); } catch (err) { const rich = isRich(); - defaultRuntime.error(colorize(rich, theme.error, `Daemon status failed: ${String(err)}`)); + defaultRuntime.error(colorize(rich, theme.error, `Gateway status failed: ${String(err)}`)); defaultRuntime.exit(1); } } diff --git a/src/cli/gateway-cli.coverage.test.ts b/src/cli/gateway-cli.coverage.test.ts index d6ea4a199..96437d566 100644 --- a/src/cli/gateway-cli.coverage.test.ts +++ b/src/cli/gateway-cli.coverage.test.ts @@ -118,7 +118,7 @@ describe("gateway-cli coverage", () => { expect(runtimeLogs.join("\n")).toContain('"ok": true'); }, 30_000); - it("registers gateway status and routes to gatewayStatusCommand", async () => { + it("registers gateway probe and routes to gatewayStatusCommand", async () => { runtimeLogs.length = 0; runtimeErrors.length = 0; gatewayStatusCommand.mockClear(); @@ -128,7 +128,7 @@ describe("gateway-cli coverage", () => { program.exitOverride(); registerGatewayCli(program); - await program.parseAsync(["gateway", "status", "--json"], { from: "user" }); + await program.parseAsync(["gateway", "probe", "--json"], { from: "user" }); expect(gatewayStatusCommand).toHaveBeenCalledTimes(1); }, 30_000); @@ -311,7 +311,7 @@ describe("gateway-cli coverage", () => { expect(startGatewayServer).toHaveBeenCalled(); expect(runtimeErrors.join("\n")).toContain("Gateway failed to start:"); - expect(runtimeErrors.join("\n")).toContain("clawdbot daemon stop"); + expect(runtimeErrors.join("\n")).toContain("clawdbot gateway stop"); }); it("uses env/config port when --port is omitted", async () => { diff --git a/src/cli/gateway-cli/register.ts b/src/cli/gateway-cli/register.ts index 5cfe71cd8..1f094699e 100644 --- a/src/cli/gateway-cli/register.ts +++ b/src/cli/gateway-cli/register.ts @@ -8,6 +8,14 @@ import { formatDocsLink } from "../../terminal/links.js"; import { colorize, isRich, theme } from "../../terminal/theme.js"; import { withProgress } from "../progress.js"; import { runCommandWithRuntime } from "../cli-utils.js"; +import { + runDaemonInstall, + runDaemonRestart, + runDaemonStart, + runDaemonStatus, + runDaemonStop, + runDaemonUninstall, +} from "../daemon-cli.js"; import { callGatewayCli, gatewayCallOpts } from "./call.js"; import type { GatewayDiscoverOpts } from "./discover.js"; import { @@ -62,13 +70,73 @@ export function registerGatewayCli(program: Command) { ), ); - // Back-compat: legacy launchd plists used gateway-daemon; keep hidden alias. addGatewayRunCommand( - program - .command("gateway-daemon", { hidden: true }) - .description("Run the WebSocket Gateway as a long-lived daemon"), + gateway.command("run").description("Run the WebSocket Gateway (foreground)"), ); + gateway + .command("status") + .description("Show gateway service status + probe the Gateway") + .option("--url ", "Gateway WebSocket URL (defaults to config/remote/local)") + .option("--token ", "Gateway token (if required)") + .option("--password ", "Gateway password (password auth)") + .option("--timeout ", "Timeout in ms", "10000") + .option("--no-probe", "Skip RPC probe") + .option("--deep", "Scan system-level services", false) + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonStatus({ + rpc: opts, + probe: Boolean(opts.probe), + deep: Boolean(opts.deep), + json: Boolean(opts.json), + }); + }); + + gateway + .command("install") + .description("Install the Gateway service (launchd/systemd/schtasks)") + .option("--port ", "Gateway port") + .option("--runtime ", "Daemon runtime (node|bun). Default: node") + .option("--token ", "Gateway token (token auth)") + .option("--force", "Reinstall/overwrite if already installed", false) + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonInstall(opts); + }); + + gateway + .command("uninstall") + .description("Uninstall the Gateway service (launchd/systemd/schtasks)") + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonUninstall(opts); + }); + + gateway + .command("start") + .description("Start the Gateway service (launchd/systemd/schtasks)") + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonStart(opts); + }); + + gateway + .command("stop") + .description("Stop the Gateway service (launchd/systemd/schtasks)") + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonStop(opts); + }); + + gateway + .command("restart") + .description("Restart the Gateway service (launchd/systemd/schtasks)") + .option("--json", "Output JSON", false) + .action(async (opts) => { + await runDaemonRestart(opts); + }); + gatewayCallOpts( gateway .command("call") @@ -121,7 +189,7 @@ export function registerGatewayCli(program: Command) { ); gateway - .command("status") + .command("probe") .description("Show gateway reachability + discovery + health + status summary (local + remote)") .option("--url ", "Explicit Gateway WebSocket URL (still probes localhost)") .option("--ssh ", "SSH target for remote gateway tunnel (user@host or user@host:port)") diff --git a/src/cli/gateway-cli/run.ts b/src/cli/gateway-cli/run.ts index 211b4c2c4..e75899fb4 100644 --- a/src/cli/gateway-cli/run.ts +++ b/src/cli/gateway-cli/run.ts @@ -278,7 +278,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) { ) { const errMessage = describeUnknownError(err); defaultRuntime.error( - `Gateway failed to start: ${errMessage}\nIf the gateway is supervised, stop it with: ${formatCliCommand("clawdbot daemon stop")}`, + `Gateway failed to start: ${errMessage}\nIf the gateway is supervised, stop it with: ${formatCliCommand("clawdbot gateway stop")}`, ); try { const diagnostics = await inspectPortUsage(port); diff --git a/src/cli/gateway-cli/shared.ts b/src/cli/gateway-cli/shared.ts index 3105a94e6..1170ac35f 100644 --- a/src/cli/gateway-cli/shared.ts +++ b/src/cli/gateway-cli/shared.ts @@ -68,21 +68,21 @@ export function renderGatewayServiceStopHints(env: NodeJS.ProcessEnv = process.e switch (process.platform) { case "darwin": return [ - `Tip: ${formatCliCommand("clawdbot daemon stop")}`, + `Tip: ${formatCliCommand("clawdbot gateway stop")}`, `Or: launchctl bootout gui/$UID/${resolveGatewayLaunchAgentLabel(profile)}`, ]; case "linux": return [ - `Tip: ${formatCliCommand("clawdbot daemon stop")}`, + `Tip: ${formatCliCommand("clawdbot gateway stop")}`, `Or: systemctl --user stop ${resolveGatewaySystemdServiceName(profile)}.service`, ]; case "win32": return [ - `Tip: ${formatCliCommand("clawdbot daemon stop")}`, + `Tip: ${formatCliCommand("clawdbot gateway stop")}`, `Or: schtasks /End /TN "${resolveGatewayWindowsTaskName(profile)}"`, ]; default: - return [`Tip: ${formatCliCommand("clawdbot daemon stop")}`]; + return [`Tip: ${formatCliCommand("clawdbot gateway stop")}`]; } } diff --git a/src/cli/program/config-guard.ts b/src/cli/program/config-guard.ts index f8e3576f6..eef500c59 100644 --- a/src/cli/program/config-guard.ts +++ b/src/cli/program/config-guard.ts @@ -4,7 +4,19 @@ import { colorize, isRich, theme } from "../../terminal/theme.js"; import type { RuntimeEnv } from "../../runtime.js"; import { formatCliCommand } from "../command-format.js"; -const ALLOWED_INVALID_COMMANDS = new Set(["doctor", "logs", "health", "help", "status", "service"]); +const ALLOWED_INVALID_COMMANDS = new Set(["doctor", "logs", "health", "help", "status"]); +const ALLOWED_INVALID_GATEWAY_SUBCOMMANDS = new Set([ + "status", + "probe", + "health", + "discover", + "call", + "install", + "uninstall", + "start", + "stop", + "restart", +]); let didRunDoctorConfigFlow = false; function formatConfigIssues(issues: Array<{ path: string; message: string }>): string[] { @@ -25,7 +37,13 @@ export async function ensureConfigReady(params: { const snapshot = await readConfigFileSnapshot(); const commandName = params.commandPath?.[0]; - const allowInvalid = commandName ? ALLOWED_INVALID_COMMANDS.has(commandName) : false; + const subcommandName = params.commandPath?.[1]; + const allowInvalid = commandName + ? ALLOWED_INVALID_COMMANDS.has(commandName) || + (commandName === "gateway" && + subcommandName && + ALLOWED_INVALID_GATEWAY_SUBCOMMANDS.has(subcommandName)) + : false; const issues = snapshot.exists && !snapshot.valid ? formatConfigIssues(snapshot.issues) : []; const legacyIssues = snapshot.legacyIssues.length > 0 diff --git a/src/cli/program/register.subclis.ts b/src/cli/program/register.subclis.ts index b13a4c76f..bc2496b70 100644 --- a/src/cli/program/register.subclis.ts +++ b/src/cli/program/register.subclis.ts @@ -36,14 +36,6 @@ const entries: SubCliEntry[] = [ mod.registerAcpCli(program); }, }, - { - name: "daemon", - description: "Manage the gateway daemon", - register: async (program) => { - const mod = await import("../daemon-cli.js"); - mod.registerDaemonCli(program); - }, - }, { name: "gateway", description: "Gateway control", diff --git a/src/cli/update-cli.ts b/src/cli/update-cli.ts index 02f92d01e..240f19ccb 100644 --- a/src/cli/update-cli.ts +++ b/src/cli/update-cli.ts @@ -785,7 +785,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { if (result.reason === "not-git-install") { defaultRuntime.log( theme.warn( - `Skipped: this Clawdbot install isn't a git checkout, and the package manager couldn't be detected. Update via your package manager, then run \`${formatCliCommand("clawdbot doctor")}\` and \`${formatCliCommand("clawdbot daemon restart")}\`.`, + `Skipped: this Clawdbot install isn't a git checkout, and the package manager couldn't be detected. Update via your package manager, then run \`${formatCliCommand("clawdbot doctor")}\` and \`${formatCliCommand("clawdbot gateway restart")}\`.`, ), ); defaultRuntime.log( @@ -877,11 +877,11 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { defaultRuntime.log(theme.warn("Skipping plugin updates: config is invalid.")); } - // Restart daemon if requested + // Restart service if requested if (opts.restart) { if (!opts.json) { defaultRuntime.log(""); - defaultRuntime.log(theme.heading("Restarting daemon...")); + defaultRuntime.log(theme.heading("Restarting service...")); } try { const { runDaemonRestart } = await import("./daemon-cli.js"); @@ -905,7 +905,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { defaultRuntime.log(theme.warn(`Daemon restart failed: ${String(err)}`)); defaultRuntime.log( theme.muted( - `You may need to restart the daemon manually: ${formatCliCommand("clawdbot daemon restart")}`, + `You may need to restart the service manually: ${formatCliCommand("clawdbot gateway restart")}`, ), ); } @@ -915,13 +915,13 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise { if (result.mode === "npm" || result.mode === "pnpm") { defaultRuntime.log( theme.muted( - `Tip: Run \`${formatCliCommand("clawdbot doctor")}\`, then \`${formatCliCommand("clawdbot daemon restart")}\` to apply updates to a running gateway.`, + `Tip: Run \`${formatCliCommand("clawdbot doctor")}\`, then \`${formatCliCommand("clawdbot gateway restart")}\` to apply updates to a running gateway.`, ), ); } else { defaultRuntime.log( theme.muted( - `Tip: Run \`${formatCliCommand("clawdbot daemon restart")}\` to apply updates to a running gateway.`, + `Tip: Run \`${formatCliCommand("clawdbot gateway restart")}\` to apply updates to a running gateway.`, ), ); } @@ -937,7 +937,7 @@ export function registerUpdateCli(program: Command) { .command("update") .description("Update Clawdbot to the latest version") .option("--json", "Output result as JSON", false) - .option("--restart", "Restart the gateway daemon after a successful update", false) + .option("--restart", "Restart the gateway service after a successful update", false) .option("--channel ", "Persist update channel (git + npm)") .option("--tag ", "Override npm dist-tag or version for this update") .option("--timeout ", "Timeout for each update step in seconds (default: 1200)") @@ -948,7 +948,7 @@ export function registerUpdateCli(program: Command) { ["clawdbot update --channel beta", "Switch to beta channel (git + npm)"], ["clawdbot update --channel dev", "Switch to dev channel (git + npm)"], ["clawdbot update --tag beta", "One-off update to a dist-tag or version"], - ["clawdbot update --restart", "Update and restart the daemon"], + ["clawdbot update --restart", "Update and restart the service"], ["clawdbot update --json", "Output result as JSON"], ["clawdbot update --yes", "Non-interactive (accept downgrade prompts)"], ["clawdbot --update", "Shorthand for clawdbot update"], diff --git a/src/commands/configure.daemon.ts b/src/commands/configure.daemon.ts index 44f6ed457..7115d49a4 100644 --- a/src/commands/configure.daemon.ts +++ b/src/commands/configure.daemon.ts @@ -37,14 +37,14 @@ export async function maybeInstallDaemon(params: { ); if (action === "restart") { await withProgress( - { label: "Gateway daemon", indeterminate: true, delayMs: 0 }, + { label: "Gateway service", indeterminate: true, delayMs: 0 }, async (progress) => { - progress.setLabel("Restarting Gateway daemon…"); + progress.setLabel("Restarting Gateway service…"); await service.restart({ env: process.env, stdout: process.stdout, }); - progress.setLabel("Gateway daemon restarted."); + progress.setLabel("Gateway service restarted."); }, ); shouldCheckLinger = true; @@ -53,11 +53,11 @@ export async function maybeInstallDaemon(params: { if (action === "skip") return; if (action === "reinstall") { await withProgress( - { label: "Gateway daemon", indeterminate: true, delayMs: 0 }, + { label: "Gateway service", indeterminate: true, delayMs: 0 }, async (progress) => { - progress.setLabel("Uninstalling Gateway daemon…"); + progress.setLabel("Uninstalling Gateway service…"); await service.uninstall({ env: process.env, stdout: process.stdout }); - progress.setLabel("Gateway daemon uninstalled."); + progress.setLabel("Gateway service uninstalled."); }, ); } @@ -66,12 +66,12 @@ export async function maybeInstallDaemon(params: { if (shouldInstall) { let installError: string | null = null; await withProgress( - { label: "Gateway daemon", indeterminate: true, delayMs: 0 }, + { label: "Gateway service", indeterminate: true, delayMs: 0 }, async (progress) => { if (!params.daemonRuntime) { daemonRuntime = guardCancel( await select({ - message: "Gateway daemon runtime", + message: "Gateway service runtime", options: GATEWAY_DAEMON_RUNTIME_OPTIONS, initialValue: DEFAULT_GATEWAY_DAEMON_RUNTIME, }), @@ -79,7 +79,7 @@ export async function maybeInstallDaemon(params: { ) as GatewayDaemonRuntime; } - progress.setLabel("Preparing Gateway daemon…"); + progress.setLabel("Preparing Gateway service…"); const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({ env: process.env, @@ -89,7 +89,7 @@ export async function maybeInstallDaemon(params: { warn: (message, title) => note(message, title), }); - progress.setLabel("Installing Gateway daemon…"); + progress.setLabel("Installing Gateway service…"); try { await service.install({ env: process.env, @@ -98,15 +98,15 @@ export async function maybeInstallDaemon(params: { workingDirectory, environment, }); - progress.setLabel("Gateway daemon installed."); + progress.setLabel("Gateway service installed."); } catch (err) { installError = err instanceof Error ? err.message : String(err); - progress.setLabel("Gateway daemon install failed."); + progress.setLabel("Gateway service install failed."); } }, ); if (installError) { - note("Gateway daemon install failed: " + installError, "Gateway"); + note("Gateway service install failed: " + installError, "Gateway"); note(gatewayInstallErrorHint(), "Gateway"); return; } diff --git a/src/commands/configure.wizard.ts b/src/commands/configure.wizard.ts index 40b8a5934..e72ddb5a3 100644 --- a/src/commands/configure.wizard.ts +++ b/src/commands/configure.wizard.ts @@ -359,7 +359,7 @@ export async function runConfigureWizard( if (!selected.includes("gateway")) { const portInput = guardCancel( await text({ - message: "Gateway port for daemon install", + message: "Gateway port for service install", initialValue: String(gatewayPort), validate: (value) => (Number.isFinite(Number(value)) ? undefined : "Invalid port"), }), @@ -481,7 +481,7 @@ export async function runConfigureWizard( if (!didConfigureGateway) { const portInput = guardCancel( await text({ - message: "Gateway port for daemon install", + message: "Gateway port for service install", initialValue: String(gatewayPort), validate: (value) => (Number.isFinite(Number(value)) ? undefined : "Invalid port"), }), diff --git a/src/commands/daemon-install-helpers.test.ts b/src/commands/daemon-install-helpers.test.ts index 7f6598c66..22ae7f24d 100644 --- a/src/commands/daemon-install-helpers.test.ts +++ b/src/commands/daemon-install-helpers.test.ts @@ -100,6 +100,6 @@ describe("buildGatewayInstallPlan", () => { describe("gatewayInstallErrorHint", () => { it("returns platform-specific hints", () => { expect(gatewayInstallErrorHint("win32")).toContain("Run as administrator"); - expect(gatewayInstallErrorHint("linux")).toContain("clawdbot daemon install"); + expect(gatewayInstallErrorHint("linux")).toContain("clawdbot gateway install"); }); }); diff --git a/src/commands/daemon-install-helpers.ts b/src/commands/daemon-install-helpers.ts index 19a129ccf..26fe7ada5 100644 --- a/src/commands/daemon-install-helpers.ts +++ b/src/commands/daemon-install-helpers.ts @@ -65,6 +65,6 @@ export async function buildGatewayInstallPlan(params: { 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 \`${formatCliCommand("clawdbot daemon install")}\` after fixing the error.`; + ? "Tip: rerun from an elevated PowerShell (Start → type PowerShell → right-click → Run as administrator) or skip service install." + : `Tip: rerun \`${formatCliCommand("clawdbot gateway install")}\` after fixing the error.`; } diff --git a/src/commands/doctor-format.ts b/src/commands/doctor-format.ts index 535937e10..2e5016b6e 100644 --- a/src/commands/doctor-format.ts +++ b/src/commands/doctor-format.ts @@ -70,10 +70,10 @@ export function buildGatewayRuntimeHints( hints.push( `LaunchAgent label cached but plist missing. Clear with: launchctl bootout gui/$UID/${label}`, ); - hints.push(`Then reinstall: ${formatCliCommand("clawdbot daemon install", env)}`); + hints.push(`Then reinstall: ${formatCliCommand("clawdbot gateway install", env)}`); } if (runtime.missingUnit) { - hints.push(`Service not installed. Run: ${formatCliCommand("clawdbot daemon install", env)}`); + hints.push(`Service not installed. Run: ${formatCliCommand("clawdbot gateway install", env)}`); if (fileLog) hints.push(`File logs: ${fileLog}`); return hints; } diff --git a/src/commands/doctor-gateway-daemon-flow.ts b/src/commands/doctor-gateway-daemon-flow.ts index fbf9c0ea0..83a4f515e 100644 --- a/src/commands/doctor-gateway-daemon-flow.ts +++ b/src/commands/doctor-gateway-daemon-flow.ts @@ -139,16 +139,16 @@ export async function maybeRepairGatewayDaemon(params: { return; } } - note("Gateway daemon not installed.", "Gateway"); + note("Gateway service not installed.", "Gateway"); if (params.cfg.gateway?.mode !== "remote") { const install = await params.prompter.confirmSkipInNonInteractive({ - message: "Install gateway daemon now?", + message: "Install gateway service now?", initialValue: true, }); if (install) { const daemonRuntime = await params.prompter.select( { - message: "Gateway daemon runtime", + message: "Gateway service runtime", options: GATEWAY_DAEMON_RUNTIME_OPTIONS, initialValue: DEFAULT_GATEWAY_DAEMON_RUNTIME, }, @@ -171,7 +171,7 @@ export async function maybeRepairGatewayDaemon(params: { environment, }); } catch (err) { - note(`Gateway daemon install failed: ${String(err)}`, "Gateway"); + note(`Gateway service install failed: ${String(err)}`, "Gateway"); note(gatewayInstallErrorHint(), "Gateway"); } } @@ -193,7 +193,7 @@ export async function maybeRepairGatewayDaemon(params: { if (serviceRuntime?.status !== "running") { const start = await params.prompter.confirmSkipInNonInteractive({ - message: "Start gateway daemon now?", + message: "Start gateway service now?", initialValue: true, }); if (start) { @@ -208,14 +208,14 @@ export async function maybeRepairGatewayDaemon(params: { if (process.platform === "darwin") { const label = resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE); note( - `LaunchAgent loaded; stopping requires "${formatCliCommand("clawdbot daemon stop")}" or launchctl bootout gui/$UID/${label}.`, + `LaunchAgent loaded; stopping requires "${formatCliCommand("clawdbot gateway stop")}" or launchctl bootout gui/$UID/${label}.`, "Gateway", ); } if (serviceRuntime?.status === "running") { const restart = await params.prompter.confirmSkipInNonInteractive({ - message: "Restart gateway daemon now?", + message: "Restart gateway service now?", initialValue: true, }); if (restart) { diff --git a/src/commands/doctor-gateway-services.ts b/src/commands/doctor-gateway-services.ts index 24395ff69..e3005428d 100644 --- a/src/commands/doctor-gateway-services.ts +++ b/src/commands/doctor-gateway-services.ts @@ -97,7 +97,7 @@ export async function maybeMigrateLegacyGatewayService( const daemonRuntime = await prompter.select( { - message: "Gateway daemon runtime", + message: "Gateway service runtime", options: GATEWAY_DAEMON_RUNTIME_OPTIONS, initialValue: DEFAULT_GATEWAY_DAEMON_RUNTIME, }, @@ -120,7 +120,7 @@ export async function maybeMigrateLegacyGatewayService( environment, }); } catch (err) { - runtime.error(`Gateway daemon install failed: ${String(err)}`); + runtime.error(`Gateway service install failed: ${String(err)}`); note(gatewayInstallErrorHint(), "Gateway"); } } diff --git a/src/commands/onboard-non-interactive/local/daemon-install.ts b/src/commands/onboard-non-interactive/local/daemon-install.ts index 895f889ef..5b2e77b63 100644 --- a/src/commands/onboard-non-interactive/local/daemon-install.ts +++ b/src/commands/onboard-non-interactive/local/daemon-install.ts @@ -21,7 +21,7 @@ export async function installGatewayDaemonNonInteractive(params: { const systemdAvailable = process.platform === "linux" ? await isSystemdUserServiceAvailable() : true; if (process.platform === "linux" && !systemdAvailable) { - runtime.log("Systemd user services are unavailable; skipping daemon install."); + runtime.log("Systemd user services are unavailable; skipping service install."); return; } @@ -48,7 +48,7 @@ export async function installGatewayDaemonNonInteractive(params: { environment, }); } catch (err) { - runtime.error(`Gateway daemon install failed: ${String(err)}`); + runtime.error(`Gateway service install failed: ${String(err)}`); runtime.log(gatewayInstallErrorHint()); return; } diff --git a/src/commands/status.command.ts b/src/commands/status.command.ts index a857c78bf..1ce771ac8 100644 --- a/src/commands/status.command.ts +++ b/src/commands/status.command.ts @@ -574,6 +574,6 @@ export async function statusCommand( if (gatewayReachable) { runtime.log(` Need to test channels? ${formatCliCommand("clawdbot status --deep")}`); } else { - runtime.log(` Fix reachability first: ${formatCliCommand("clawdbot gateway status")}`); + runtime.log(` Fix reachability first: ${formatCliCommand("clawdbot gateway probe")}`); } } diff --git a/src/commands/uninstall.ts b/src/commands/uninstall.ts index 8cc1aff68..23b410606 100644 --- a/src/commands/uninstall.ts +++ b/src/commands/uninstall.ts @@ -51,7 +51,7 @@ function buildScopeSelection(opts: UninstallOptions): { async function stopAndUninstallService(runtime: RuntimeEnv): Promise { if (isNixMode) { - runtime.error("Nix mode detected; daemon uninstall is disabled."); + runtime.error("Nix mode detected; service uninstall is disabled."); return false; } const service = resolveGatewayService(); diff --git a/src/daemon/systemd-hints.ts b/src/daemon/systemd-hints.ts index 8499a718b..663a9d233 100644 --- a/src/daemon/systemd-hints.ts +++ b/src/daemon/systemd-hints.ts @@ -22,6 +22,6 @@ export function renderSystemdUnavailableHints(options: { wsl?: boolean } = {}): } return [ "systemd user services are unavailable; install/enable systemd or run the gateway under your supervisor.", - `If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("clawdbot daemon")}\`.`, + `If you're in a container, run the gateway in the foreground instead of \`${formatCliCommand("clawdbot gateway")}\`.`, ]; } diff --git a/src/infra/ports-format.ts b/src/infra/ports-format.ts index 6bf7db4bd..e6f29edd7 100644 --- a/src/infra/ports-format.ts +++ b/src/infra/ports-format.ts @@ -21,7 +21,7 @@ export function buildPortHints(listeners: PortListener[], port: number): string[ const hints: string[] = []; if (kinds.has("gateway")) { hints.push( - `Gateway already running locally. Stop it (${formatCliCommand("clawdbot daemon stop")}) or use a different port.`, + `Gateway already running locally. Stop it (${formatCliCommand("clawdbot gateway stop")}) or use a different port.`, ); } if (kinds.has("ssh")) {