const systemdAvailable =
process.platform === "linux" ? await isSystemdUserServiceAvailable() : true; if (process.platform === "linux" && !systemdAvailable) {
await prompter.note( "Systemd user services are unavailable. Skipping lingering checks and service install.", "Systemd",
);
}
if (process.platform === "linux" && systemdAvailable) { const { ensureSystemdUserLingerInteractive } = await import("../commands/systemd-linger.js");
await ensureSystemdUserLingerInteractive({
runtime,
prompter: {
confirm: prompter.confirm,
note: prompter.note,
},
reason: "Linux installs use a systemd user service by default. Without lingering, systemd stops the user session on logout/idle and kills the Gateway.",
requireConfirm: false,
});
}
if (process.platform === "linux" && !systemdAvailable && installDaemon) {
await prompter.note( "Systemd user services are unavailable; skipping service install. Use your container supervisor or `docker compose up -d`.", "Gateway service",
);
installDaemon = false;
}
let controlUiOpened = false;
let controlUiOpenHint: string | undefined;
let seededInBackground = false;
let hatchChoice: "tui" | "web" | "later" | null = null;
let launchedTui = false;
if (!opts.skipUi) { if (hasBootstrap) {
await prompter.note(
[ "This is the defining action that makes your agent you.", "Please take your time.", "The more you tell it, the better the experience will be.", 'We will send: "Wake up, my friend!"',
].join("\n"), "Start TUI (best option!)",
);
}
if (gatewayProbe.ok) {
await prompter.note(
[ "Gateway token: shared auth for the Gateway + Control UI.", "Stored in: $OPENCLAW_CONFIG_PATH (default: ~/.openclaw/openclaw.json) under gateway.auth.token, or in OPENCLAW_GATEWAY_TOKEN.",
`View token: ${formatCliCommand("openclaw config get gateway.auth.token")}`,
`Generate token: ${formatCliCommand("openclaw doctor --generate-gateway-token")}`, "Web UI keeps dashboard URL tokens in memory for the current tab and strips them from the URL after load.",
`Open the dashboard anytime: ${formatCliCommand("openclaw dashboard --no-open")}`, "If prompted: paste the token into Control UI settings (or use the tokenized dashboard URL).",
].join("\n"), "Token",
);
}
const hatchOptions: { value: "tui" | "web" | "later"; label: string }[] = [
{ value: "tui", label: "Hatch in Terminal (recommended)" },
...(gatewayProbe.ok ? [{ value: "web" as const, label: "Open the Web UI" }] : []),
{ value: "later", label: "Do this later" },
];
hatchChoice = await prompter.select({
message: "How do you want to hatch your bot?",
options: hatchOptions,
initialValue: "tui",
});
if (hatchChoice === "tui") {
restoreTerminalState("pre-setup tui", { resumeStdinIfPaused: true }); try {
await launchTuiCli({
local: true,
deliver: false,
message: hasBootstrap ? "Wake up, my friend!" : undefined,
});
} finally {
restoreTerminalState("post-setup tui", { resumeStdinIfPaused: true });
}
launchedTui = true;
} elseif (hatchChoice === "web") { const browserSupport = await detectBrowserOpenSupport(); if (browserSupport.ok) {
controlUiOpened = await openUrl(authedUrl); if (!controlUiOpened) {
controlUiOpenHint = formatControlUiSshHint({
port: settings.port,
basePath: controlUiBasePath,
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
});
}
} else {
controlUiOpenHint = formatControlUiSshHint({
port: settings.port,
basePath: controlUiBasePath,
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
});
}
await prompter.note(
[
`Dashboard link (with token): ${authedUrl}`,
controlUiOpened
? "Opened in your browser. Keep that tab to control OpenClaw."
: "Copy/paste this URL in a browser on this machine to control OpenClaw.",
controlUiOpenHint,
]
.filter(Boolean)
.join("\n"), "Dashboard ready",
);
} else {
await prompter.note(
`When you're ready: ${formatCliCommand("openclaw dashboard --no-open")}`, "Later",
);
}
} elseif (opts.skipUi) {
await prompter.note("Skipping Control UI/TUI prompts.", "Control UI");
}
await prompter.note(
[
`Dashboard link (with token): ${authedUrl}`,
controlUiOpened
? "Opened in your browser. Keep that tab to control OpenClaw."
: "Copy/paste this URL in a browser on this machine to control OpenClaw.",
controlUiOpenHint,
]
.filter(Boolean)
.join("\n"), "Dashboard ready",
);
}
const codexNativeSummary = describeCodexNativeWebSearch(nextConfig); const webSearchProvider = nextConfig.tools?.web?.search?.provider; const webSearchEnabled = nextConfig.tools?.web?.search?.enabled; const configuredSearchProviders = listConfiguredWebSearchProviders({ config: nextConfig }); if (webSearchProvider) { const { resolveExistingKey, hasExistingKey, hasKeyInEnv } = await loadOnboardSearchModule(); const entry = configuredSearchProviders.find((e) => e.id === webSearchProvider); const label = entry?.label ?? webSearchProvider; const storedKey = entry ? resolveExistingKey(nextConfig, webSearchProvider) : undefined; const keyConfigured = entry ? hasExistingKey(nextConfig, webSearchProvider) : false; const envAvailable = entry ? hasKeyInEnv(entry) : false; const hasKey = keyConfigured || envAvailable; const keySource = storedKey
? "API key: stored in config."
: keyConfigured
? "API key: configured via secret reference."
: envAvailable
? `API key: provided via ${entry?.envVars.join(" / ")} env var.`
: undefined; if (!entry) {
await prompter.note(
[
`Web search provider ${label} is selected but unavailable under the current plugin policy.`, "web_search will not work until the provider is re-enabled or a different provider is selected.",
` ${formatCliCommand("openclaw configure --section web")}`, "", "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
} elseif (webSearchEnabled !== false && hasKey) {
await prompter.note(
[ "Web search is enabled, so your agent can look things up online when needed.", "",
`Provider: ${label}`,
...(keySource ? [keySource] : []), "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
} elseif (!hasKey) {
await prompter.note(
[
`Provider ${label} is selected but no API key was found.`, "web_search will not work until a key is added.",
` ${formatCliCommand("openclaw configure --section web")}`, "",
`Get your key at: ${entry?.signupUrl ?? "https://docs.openclaw.ai/tools/web"}`, "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
} else {
await prompter.note(
[
`Web search (${label}) is configured but disabled.`,
`Re-enable: ${formatCliCommand("openclaw configure --section web")}`, "", "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
}
} else { // Legacy configs may have a working key (e.g. apiKey or BRAVE_API_KEY) without // an explicit provider. Runtime auto-detects these, so avoid saying "skipped". const { hasExistingKey, hasKeyInEnv } = await loadOnboardSearchModule(); const legacyDetected = configuredSearchProviders.find(
(e) => hasExistingKey(nextConfig, e.id) || hasKeyInEnv(e),
); if (legacyDetected) {
await prompter.note(
[
`Web search is available via ${legacyDetected.label} (auto-detected).`, "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
} elseif (codexNativeSummary) {
await prompter.note(
[ "Managed web search provider was skipped.",
codexNativeSummary, "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
} else {
await prompter.note(
[ "Web search was skipped. You can enable it later:",
` ${formatCliCommand("openclaw configure --section web")}`, "", "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Web search",
);
}
}
if (codexNativeSummary) {
await prompter.note(
[
codexNativeSummary, "Used only for Codex-capable models.", "Docs: https://docs.openclaw.ai/tools/web",
].join("\n"), "Codex native search",
);
}
await prompter.outro(
controlUiOpened
? "Onboarding complete. Dashboard opened; keep that tab to control OpenClaw."
: seededInBackground
? "Onboarding complete. Web UI seeded in the background; open it anytime with the dashboard link above."
: "Onboarding complete. Use the dashboard link above to control OpenClaw.",
);
return { launchedTui };
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-04)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.