fix(onboarding): daemon progress + web search setup

This commit is contained in:
Peter Steinberger
2026-01-15 08:28:37 +00:00
parent f1ac18933c
commit a39bb4310c
3 changed files with 173 additions and 93 deletions

View File

@@ -8,6 +8,7 @@ import {
} from "../daemon/runtime-paths.js";
import { resolveGatewayService } from "../daemon/service.js";
import { buildServiceEnvironment } from "../daemon/service-env.js";
import { withProgress } from "../cli/progress.js";
import type { RuntimeEnv } from "../runtime.js";
import { note } from "../terminal/note.js";
import { confirm, select } from "./configure.shared.js";
@@ -43,63 +44,89 @@ export async function maybeInstallDaemon(params: {
params.runtime,
);
if (action === "restart") {
await service.restart({
profile: process.env.CLAWDBOT_PROFILE,
stdout: process.stdout,
});
await withProgress(
{ label: "Gateway daemon", indeterminate: true, delayMs: 0 },
async (progress) => {
progress.setLabel("Restarting Gateway daemon…");
await service.restart({
profile: process.env.CLAWDBOT_PROFILE,
stdout: process.stdout,
});
progress.setLabel("Gateway daemon restarted.");
},
);
shouldCheckLinger = true;
shouldInstall = false;
}
if (action === "skip") return;
if (action === "reinstall") {
await service.uninstall({ env: process.env, stdout: process.stdout });
await withProgress(
{ label: "Gateway daemon", indeterminate: true, delayMs: 0 },
async (progress) => {
progress.setLabel("Uninstalling Gateway daemon…");
await service.uninstall({ env: process.env, stdout: process.stdout });
progress.setLabel("Gateway daemon uninstalled.");
},
);
}
}
if (shouldInstall) {
if (!params.daemonRuntime) {
daemonRuntime = guardCancel(
await select({
message: "Gateway daemon runtime",
options: GATEWAY_DAEMON_RUNTIME_OPTIONS,
initialValue: DEFAULT_GATEWAY_DAEMON_RUNTIME,
}),
params.runtime,
) as GatewayDaemonRuntime;
}
const devMode =
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,
port: params.port,
token: params.gatewayToken,
launchdLabel:
process.platform === "darwin"
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
});
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
});
await withProgress(
{ label: "Gateway daemon", indeterminate: true, delayMs: 0 },
async (progress) => {
if (!params.daemonRuntime) {
daemonRuntime = guardCancel(
await select({
message: "Gateway daemon runtime",
options: GATEWAY_DAEMON_RUNTIME_OPTIONS,
initialValue: DEFAULT_GATEWAY_DAEMON_RUNTIME,
}),
params.runtime,
) as GatewayDaemonRuntime;
}
progress.setLabel("Preparing Gateway daemon…");
const devMode =
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,
port: params.port,
token: params.gatewayToken,
launchdLabel:
process.platform === "darwin"
? resolveGatewayLaunchAgentLabel(process.env.CLAWDBOT_PROFILE)
: undefined,
});
progress.setLabel("Installing Gateway daemon…");
await service.install({
env: process.env,
stdout: process.stdout,
programArguments,
workingDirectory,
environment,
});
progress.setLabel("Gateway daemon installed.");
},
);
shouldCheckLinger = true;
}

View File

@@ -98,9 +98,18 @@ async function promptWebToolsConfig(
const existingFetch = nextConfig.tools?.web?.fetch;
const hasSearchKey = Boolean(existingSearch?.apiKey);
note(
[
"Web search lets your agent look things up online using the `web_search` tool.",
"It requires a Brave Search API key (you can store it in the config or set BRAVE_API_KEY in the Gateway environment).",
"Docs: https://docs.clawd.bot/tools/web",
].join("\n"),
"Web search",
);
const enableSearch = guardCancel(
await confirm({
message: "Enable web_search (Brave Search API)?",
message: "Enable web_search (Brave Search)?",
initialValue: existingSearch?.enabled ?? hasSearchKey,
}),
runtime,
@@ -116,7 +125,7 @@ async function promptWebToolsConfig(
await text({
message: hasSearchKey
? "Brave Search API key (leave blank to keep current or use BRAVE_API_KEY)"
: "Brave Search API key (leave blank to use BRAVE_API_KEY)",
: "Brave Search API key (paste it here; leave blank to use BRAVE_API_KEY)",
placeholder: hasSearchKey ? "Leave blank to keep current" : "BSA...",
}),
runtime,
@@ -127,7 +136,8 @@ async function promptWebToolsConfig(
} else if (!hasSearchKey) {
note(
[
"No key stored. web_search needs BRAVE_API_KEY or tools.web.search.apiKey.",
"No key stored yet, so web_search will stay unavailable.",
"Store a key here or set BRAVE_API_KEY in the Gateway environment.",
"Docs: https://docs.clawd.bot/tools/web",
].join("\n"),
"Web search",